aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRetro-Junk2016-07-30 23:15:32 +0300
committerEugene Sandulenko2017-01-25 22:41:46 +0100
commitecf0d041045214933b9ef10d490bf62f3c7add99 (patch)
treeeaf091312dc898a15ffedb555588297d2234d871
parente25bac9690f2802bce932d9b5490e2d5336be818 (diff)
downloadscummvm-rg350-ecf0d041045214933b9ef10d490bf62f3c7add99.tar.gz
scummvm-rg350-ecf0d041045214933b9ef10d490bf62f3c7add99.tar.bz2
scummvm-rg350-ecf0d041045214933b9ef10d490bf62f3c7add99.zip
CRYO: Lost Eden game engine initial commit
-rw-r--r--engines/cryo/CLError.c3
-rw-r--r--engines/cryo/CLHNM.c874
-rw-r--r--engines/cryo/CLSouNdRaw.c57
-rw-r--r--engines/cryo/CryoLib.h181
-rw-r--r--engines/cryo/CryoLibStub.c604
-rw-r--r--engines/cryo/LempelZiv.cpp7
-rw-r--r--engines/cryo/LempelZiv.h102
-rw-r--r--engines/cryo/ResourceManager.cpp116
-rw-r--r--engines/cryo/ResourceManager.h77
-rw-r--r--engines/cryo/bugs.txt10
-rw-r--r--engines/cryo/clsoundgroup.c117
-rw-r--r--engines/cryo/configure.engine3
-rw-r--r--engines/cryo/cryo.cpp81
-rw-r--r--engines/cryo/cryo.h62
-rw-r--r--engines/cryo/defs.h1399
-rw-r--r--engines/cryo/detection.cpp131
-rw-r--r--engines/cryo/eden.cpp9457
-rw-r--r--engines/cryo/eden.h14
-rw-r--r--engines/cryo/gameflow.txt24
-rw-r--r--engines/cryo/module.mk14
-rw-r--r--engines/cryo/platdefs.h26
-rw-r--r--engines/cryo/readme.txt80
22 files changed, 13439 insertions, 0 deletions
diff --git a/engines/cryo/CLError.c b/engines/cryo/CLError.c
new file mode 100644
index 0000000000..85abfefa70
--- /dev/null
+++ b/engines/cryo/CLError.c
@@ -0,0 +1,3 @@
+#include "cryolib.h"
+
+short __debug, __libError, __osError;
diff --git a/engines/cryo/CLHNM.c b/engines/cryo/CLHNM.c
new file mode 100644
index 0000000000..3ab3f6515e
--- /dev/null
+++ b/engines/cryo/CLHNM.c
@@ -0,0 +1,874 @@
+#include "cryolib.h"
+
+static short safe_palette = 0;
+static short pred_r = 0, pred_l = 0;
+static short use_adpcm = 0;
+static float hnm_rate = 0.0;
+static float next_frame_time = 0.0;
+static float expected_frame_time = 0.0;
+static float time_drift = 0.0;
+static short use_mono = 0;
+static short use_sound = 0;
+static short use_sound_sync = 0;
+static short pending_sounds = 0;
+static short sound_started = 0;
+static short preserve_color0 = 0;
+static soundchannel_t *soundChannel_adpcm = 0;
+static soundgroup_t *soundGroup_adpcm = 0;
+static soundchannel_t *soundChannel = 0;
+static soundgroup_t *soundGroup = 0;
+static void (*custom_chunk_handler)(unsigned char *buffer, int size, short id, char h6, char h7) = 0;
+static short use_preload = 0;
+static short decomp_table[256];
+
+void CLHNM_Desentrelace320(unsigned char *frame_buffer, unsigned char *final_buffer, unsigned short height);
+
+void CLHNM_DecompLempelZiv(unsigned char *buffer, unsigned char *output)
+{
+ unsigned char *inp = buffer;
+ unsigned char *out = output;
+
+ unsigned int queue = 0;
+ int qpos = -1;
+
+ //TODO: fix for BE
+#define GetBit() ( 1 & ( (qpos >= 0) ? (queue >> qpos--) : (queue = *(unsigned int*)((inp += 4) - 4)) >> ((qpos = 30) + 1) ) )
+
+ for (;;)
+ {
+ if (GetBit())
+ {
+ *out++ = *inp++;
+ }
+ else
+ {
+ int l, o;
+ if (GetBit())
+ {
+ l = *inp & 7;
+ o = *(unsigned short*)inp >> 3; inp += 2;
+ o -= 8192;
+ if (!l)
+ l = *inp++;
+ if (!l)
+ break;
+ }
+ else
+ {
+ l = GetBit() * 2 + GetBit();
+ o = *(inp++) - 256;
+ }
+ l += 2;
+ while (l--)
+ {
+ *out = *(out + o); out++;
+ }
+ }
+ }
+
+#undef GetBit
+
+ return;
+}
+
+void CLHNM_DecompUBA(unsigned char *output, unsigned char *curr_buffer, unsigned char *prev_buffer,
+ unsigned char *input, int width, char flags)
+{
+ unsigned int code;
+ char mode, count, color;
+ unsigned short offs;
+ unsigned char *ref;
+ unsigned char *out_start = output;
+ unsigned char swap;
+ int shft1, shft2;
+// return;
+ if((flags & 1) == 0)
+ {
+ //HNM4 classic
+ int twolinesabove = -(width * 2);
+ for(;;)
+ {
+ code = PLE32(input) & 0xFFFFFF; //input++;
+ count = code & 0x1F;
+ if(count)
+ {
+ input += 3;
+ mode = (code >> 5) & 0xF;
+ offs = code >> 9;
+ //
+ swap = mode >> 3;
+ ref = ((mode & 1) ? prev_buffer : curr_buffer) + (output - out_start) + (offs * 2) - 32768;
+ if (mode & 2)
+ {
+ // ref += twolinesabove;
+ shft1 = twolinesabove + 1;
+ shft2 = 0;
+ //swap ^= 1;
+ }
+ else
+ {
+ shft1 = 0;
+ shft2 = 1;
+ }
+ while(count--)
+ {
+ unsigned char b0 = ref[shft1];
+ unsigned char b1 = ref[shft2];
+ output[swap] = b0;
+ output[swap ^ 1] = b1;
+ output += 2;
+ ref += (mode & 4) ? -2 : 2;
+ }
+ }
+ else
+ {
+ input++;
+ mode = code & 0xFF; // bits 0..4 are zero
+ switch(mode)
+ {
+ case 0:
+ *(output++) = *(input++);
+ *(output++) = *(input++);
+ break;
+ case 0x20:
+ output += 2 * *(input++);
+ break;
+ case 0x40:
+ output += 2 * (code >> 8); input += 2;
+ break;
+ case 0x60:
+ count = *(input++);
+ color = *(input++);
+ while(count--)
+ {
+ *(output++) = color;
+ *(output++) = color;
+ }
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ assert(0);
+ //HNM4 hires
+ for(;;)
+ {
+ code = PLE32(input) & 0xFFFFFF; input++;
+ count = code & 0x3F;
+ if(count)
+ {
+ mode = (code >> 5) & 0xF;
+ offs = code >> 9;
+ //
+ }
+ else
+ {
+ mode = code & 0xFF; // bits 0..5 are zero
+ switch(mode)
+ {
+ case 0x00:
+ output += *input++;
+ break;
+ case 0x40:
+ *output++ = *input++;
+ *(output++ + width) = *input++;
+ break;
+ case 0x80:
+ output += width;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ }
+}
+
+void CLHNM_Init()
+{
+ use_preload = 0;
+ custom_chunk_handler = 0;
+ preserve_color0 = 0;
+ CLNoError;
+}
+
+void CLHNM_Done()
+{
+ CLNoError;
+}
+
+void CLHNM_SetupTimer(float rate)
+{
+ hnm_rate = 100.0 / rate;
+ CLNoError;
+}
+
+void CLHNM_WaitLoop(hnm_t *hnm)
+{
+ expected_frame_time += hnm_rate;
+ next_frame_time = expected_frame_time - time_drift;
+ if(use_sound_sync && TimerTicks > 1000.0 + next_frame_time)
+ use_sound = 0;
+ while(TimerTicks < next_frame_time) ; // waste time
+ time_drift = TimerTicks - next_frame_time;
+}
+
+void CLHNM_SetupSound(short numSounds, short arg4, short sampleSize, float rate, short mode)
+{
+ soundChannel = CLSoundChannel_New(mode);
+ soundGroup = CLSoundGroup_New(numSounds, arg4, sampleSize, rate, mode);
+ if(sampleSize == 16)
+ CLSoundGroup_Reverse16All(soundGroup);
+}
+
+void CLHNM_SetupSoundADPCM(short numSounds, short arg4, short sampleSize, float rate, short mode)
+{
+ soundChannel_adpcm = CLSoundChannel_New(mode);
+ soundGroup_adpcm = CLSoundGroup_New(numSounds, arg4, sampleSize, rate, mode);
+}
+
+void CLHNM_CloseSound()
+{
+ if(soundChannel)
+ {
+ CLSoundChannel_Stop(soundChannel);
+ CLSoundChannel_Free(soundChannel);
+ soundChannel = 0;
+ }
+ if(soundGroup)
+ {
+ CLSoundGroup_Free(soundGroup);
+ soundGroup = 0;
+ }
+ if(soundChannel_adpcm)
+ {
+ CLSoundChannel_Stop(soundChannel_adpcm);
+ CLSoundChannel_Free(soundChannel_adpcm);
+ soundChannel = 0;
+ }
+ if(soundGroup_adpcm)
+ {
+ CLSoundGroup_Free(soundGroup_adpcm);
+ soundGroup = 0;
+ }
+}
+
+void CLHNM_SetForceZero2Black(short forceblack)
+{
+ preserve_color0 = forceblack;
+}
+
+hnm_t* CLHNM_New(int preload_size)
+{
+ hnm_t *hnm;
+ short i;
+
+ preload_size = 0; //TODO: let's ignore it for now
+
+ CLBeginCheck;
+ hnm = (hnm_t*)CLMemory_Alloc(sizeof(*hnm));
+ CLCheckError();
+ if(hnm)
+ {
+ if(preload_size)
+ {
+ use_preload = 1;
+
+ }
+ if(!__libError)
+ {
+ hnm->frame = 0;
+ hnm->ff_4 = 0;
+ hnm->file = 0;
+ hnm->work_buffer[0] = 0;
+ hnm->work_buffer[1] = 0;
+ hnm->final_buffer = 0;
+ hnm->read_buffer = 0;
+ hnm->ff_896 = 0;
+ hnm->total_read = 0;
+ for(i = 0;i < 256;i++)
+ {
+ hnm->palette[i].a = 0;
+ hnm->palette[i].r = 0;
+ hnm->palette[i].g = 0;
+ hnm->palette[i].b = 0;
+ }
+ }
+ else
+ CLCheckError();
+ }
+ CLEndCheck;
+ return hnm;
+}
+
+void CLHNM_Dispose(hnm_t *hnm)
+{
+ CLBeginCheck;
+
+ if(use_preload)
+ {
+
+ }
+
+ CLMemory_Free(hnm);
+ CLCheckError();
+
+ CLEndCheck;
+}
+
+
+void CLHNM_SetFile(hnm_t *hnm, file_t* file)
+{
+ hnm->file = file;
+ CLNoError;
+}
+
+void CLHNM_SetFinalBuffer(hnm_t *hnm, unsigned char *buffer)
+{
+ hnm->final_buffer = buffer;
+ CLNoError;
+}
+
+void CLHNM_AllocMemory(hnm_t *hnm)
+{
+ CLBeginCheck;
+
+ hnm->work_buffer[0] = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
+ CLCheckError();
+
+ if(!hnm->work_buffer[0])
+ goto fin;
+
+ hnm->work_buffer[1] = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
+ CLCheckError();
+
+ if(!hnm->work_buffer[1])
+ {
+ CLMemory_Free(hnm->work_buffer[0]);
+ CLCheckError();
+ hnm->work_buffer[0] = 0;
+ goto fin;
+ }
+
+ if(!use_preload)
+ {
+ hnm->read_buffer = (unsigned char*)CLMemory_Alloc(hnm->header.buffersize + 2);
+// CLCheckError();
+ if(!hnm->read_buffer)
+ {
+ CLMemory_Free(hnm->work_buffer[0]);
+ CLCheckError();
+ hnm->work_buffer[0] = 0;
+ CLMemory_Free(hnm->work_buffer[1]);
+ CLCheckError();
+ hnm->work_buffer[1] = 0;
+ }
+ }
+fin:;
+ CLEndCheck;
+}
+
+void CLHNM_DeallocMemory(hnm_t *hnm)
+{
+ CLBeginCheck;
+ if(hnm->work_buffer[0])
+ {
+ CLMemory_Free(hnm->work_buffer[0]);
+ CLCheckError();
+ hnm->work_buffer[0] = 0;
+ }
+ if(hnm->work_buffer[1])
+ {
+ CLMemory_Free(hnm->work_buffer[1]);
+ CLCheckError();
+ hnm->work_buffer[1] = 0;
+ }
+
+ if(!use_preload)
+ {
+ if(hnm->read_buffer)
+ {
+ CLMemory_Free(hnm->read_buffer);
+ CLCheckError();
+ hnm->read_buffer = 0;
+ }
+ }
+
+ CLEndCheck;
+}
+
+void CLHNM_Read(hnm_t *hnm, int size)
+{
+ long _size = size;
+ if(!use_preload)
+ {
+ CLFile_Read(*hnm->file, hnm->read_buffer, &_size);
+ }
+ else
+ {
+ }
+}
+
+void CLHNM_GiveTime(hnm_t *hnm)
+{
+ if(use_preload)
+ {
+ //stuff preload_buffer from disk
+ }
+}
+
+void CLHNM_CanLoop(hnm_t *hnm, short can_loop)
+{
+ hnm->can_loop = can_loop;
+}
+
+void CLHNM_SelectBuffers(hnm_t *hnm)
+{
+ if(hnm->frame % 2)
+ {
+ hnm->new_frame_buffer = hnm->work_buffer[1];
+ hnm->old_frame_buffer = hnm->work_buffer[0];
+ }
+ else
+ {
+ hnm->new_frame_buffer = hnm->work_buffer[0];
+ hnm->old_frame_buffer = hnm->work_buffer[1];
+ }
+}
+
+void CLHNM_ChangePalette(hnm_t *hnm)
+{
+ short mincolor, maxcolor;
+ unsigned short fst, cnt;
+ unsigned char *pal;
+ color_t *color;
+ CLPalette_GetLastPalette(hnm->palette);
+ pal = hnm->data_ptr;
+ if(*(unsigned short*)pal == 0xFFFF)
+ return;
+ mincolor = 255;
+ maxcolor = 0;
+ do
+ {
+ fst = *pal++;
+ cnt = *pal++;
+ if(cnt == 0)
+ cnt = 256;
+ debug("hnm: setting palette, fst = %d, cnt = %d, last = %d", fst, cnt, fst + cnt - 1);
+ assert(fst + cnt <= 256);
+ if (mincolor > fst)
+ mincolor = fst;
+ if(maxcolor < fst + cnt)
+ maxcolor = fst + cnt;
+ color = hnm->palette + fst;
+ if(safe_palette)
+ {
+ while(cnt--)
+ {
+ unsigned char r = *pal++;
+ unsigned char g = *pal++;
+ unsigned char b = *pal++;
+ short rr = r << 10;
+ short gg = g << 10;
+ short bb = b << 10;
+ if(color->r != rr || color->g != gg || color->b != bb)
+ CLBlitter_OneBlackFlash();
+ color->r = rr;
+ color->g = gg;
+ color->b = bb;
+ color++;
+ }
+ }
+ else
+ {
+ while(cnt--)
+ {
+ unsigned char r = *pal++;
+ unsigned char g = *pal++;
+ unsigned char b = *pal++;
+ color->r = r << 10;
+ color->g = g << 10;
+ color->b = b << 10;
+ color++;
+ }
+ }
+
+ }
+ while(*(unsigned short*)pal != 0xFFFF);
+#if 0
+ if(preserve_color0)
+ {
+ hnm->palette[0].r = 0;
+ hnm->palette[0].g = 0;
+ hnm->palette[0].b = 0;
+ }
+#endif
+// CLBlitter_Send2ScreenNextCopy(hnm->palette, mincolor, maxcolor - mincolor);
+ CLBlitter_Send2ScreenNextCopy(hnm->palette, 0, 256);
+}
+
+void CLHNM_Desentrelace(hnm_t *hnm)
+{
+ switch(hnm->header.width)
+ {
+ case 320:
+ CLHNM_Desentrelace320(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
+ CLNoError;
+ break;
+// case 480:
+// CLHNM_Desentrelace480(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
+// CLNoError;
+// break;
+ default:
+ __libError = -5;
+ __osError = 0;
+ CLCheckError();
+ }
+}
+
+void CLHNM_FlushPreloadBuffer(hnm_t *hnm)
+{
+ if(use_preload)
+ {
+ }
+}
+
+soundchannel_t* CLHNM_GetSoundChannel()
+{
+ return soundChannel;
+}
+
+
+void CLHNM_TryRead(hnm_t *hnm, int size)
+{
+ short err;
+ do
+ {
+ CLHNM_Read(hnm, size);
+ err = __libError == -6;
+ if(err)
+ CLHNM_GiveTime(hnm);
+ }
+ while(err);
+}
+
+void CLHNM_ResetInternalTimer()
+{
+ time_drift = 0.0;
+ next_frame_time = expected_frame_time = TimerTicks;
+}
+
+void CLHNM_Reset(hnm_t *hnm)
+{
+ hnm->frame = 0;
+ hnm->ff_4 = 0;
+ hnm->total_read = 0;
+ sound_started = 0;
+ pending_sounds = 0;
+ CLHNM_ResetInternalTimer();
+ CLNoError;
+}
+
+short CLHNM_LoadFrame(hnm_t *hnm)
+{
+ int chunk;
+ CLBeginCheck;
+ CLHNM_TryRead(hnm, 4);
+ CLEndCheck;
+ chunk = *(int*)hnm->read_buffer;
+ chunk = LE32(chunk);
+ chunk &= 0xFFFFFF; // upper bit - keyframe mark?
+ if(!chunk)
+ return 0;
+
+ if(use_preload)
+ {
+ }
+ else
+ {
+ if(chunk - 4 > hnm->header.buffersize)
+ {
+ __libError = -3;
+ __osError = 0;
+ CLCheckError();
+ }
+ else
+ if(use_preload && chunk - 4 > 102400)
+ {
+ __libError = -3;
+ __osError = 0;
+ CLCheckError();
+ }
+ }
+ CLBeginCheck;
+ CLHNM_TryRead(hnm, chunk - 4);
+ CLEndCheck;
+ hnm->data_ptr = hnm->read_buffer;
+ hnm->total_read += chunk;
+ return 1;
+}
+
+void CLHNM_WantsSound(short sound)
+{
+ use_sound = sound;
+}
+
+void CLHNM_LoadDecompTable(short *buffer)
+{
+ short i;
+ short e;
+ for(i = 0;i < 256;i++)
+ {
+ e = *buffer++;
+ decomp_table[i] = LE16(e);
+ }
+}
+
+void CLHNM_DecompADPCM(unsigned char *buffer, short *output, int size)
+{
+ short l = pred_l, r = pred_r;
+ size &= ~1;
+ while(size--)
+ {
+ *output++ = l += decomp_table[*buffer++];
+ *output++ = r += decomp_table[*buffer++];
+ if(l > 512 || r > 512)
+ DebugStr(" coucou");
+ }
+ pred_l = l;
+ pred_r = r;
+}
+
+void CLHNM_SoundInADPCM(short is_adpcm)
+{
+ use_adpcm = is_adpcm;
+}
+
+void CLHNM_SoundMono(short is_mono)
+{
+ use_mono = is_mono;
+}
+
+short CLHNM_NextElement(hnm_t *hnm)
+{
+ int sz;
+ short id;
+ char h6, h7;
+ short i;
+ if(hnm->frame == 0)
+ {
+ CLHNM_ResetInternalTimer();
+ pred_l = pred_r = 0;
+ }
+ if(hnm->frame == hnm->header.nframe)
+ return 0;
+ if(!CLHNM_LoadFrame(hnm))
+ return 0;
+ for(;;)
+ {
+ sz = PLE32(hnm->data_ptr) & 0xFFFFFF; hnm->data_ptr += 4;
+ id = *(short*)hnm->data_ptr; hnm->data_ptr += 2;
+ h6 = *hnm->data_ptr; hnm->data_ptr += 1;
+ h7 = *hnm->data_ptr; hnm->data_ptr += 1;
+ hnm->chunk_id = id;
+ switch(id)
+ {
+ case BE16('PL'):
+ CLHNM_ChangePalette(hnm);
+ hnm->data_ptr += sz - 8;
+ break;
+ case BE16('IZ'):
+ hnm->frame++;
+ CLHNM_SelectBuffers(hnm);
+ CLHNM_DecompLempelZiv(hnm->data_ptr + 4, hnm->new_frame_buffer);
+ switch(hnm->header.width)
+ {
+// case 320: CLBlitter_RawCopy320ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
+// case 480: CLBlitter_RawCopy480ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
+// case 640: CLBlitter_RawCopy640ASM(hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->header.height); break;
+// default: memcpy(hnm->old_frame_buffer, hnm->new_frame_buffer, hnm->header.width * hnm->header.height);
+ default: memcpy(hnm->old_frame_buffer, hnm->new_frame_buffer, hnm->header.buffersize); //TODO strange buffer size here
+ }
+ if(!(h6 & 1))
+ CLHNM_Desentrelace(hnm);
+ else
+ {
+// if(hnm->header.width == 640)
+// CLBlitter_RawCopy640(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
+// else
+ memcpy(hnm->final_buffer, hnm->new_frame_buffer, hnm->header.height); //TODO: wrong size?
+ }
+ if(use_adpcm)
+ {
+ if(!sound_started)
+ {
+ for(i = 0;i < pending_sounds;i++)
+ CLSoundGroup_PlayNextSample(soundGroup_adpcm, soundChannel);
+ sound_started = 1;
+ }
+ }
+ else
+ {
+ if(!sound_started)
+ {
+ for(i = 0;i < pending_sounds;i++)
+ CLSoundGroup_PlayNextSample(soundGroup, soundChannel);
+ sound_started = 1;
+ }
+ }
+ goto end_frame;
+ case BE16('IU'):
+ hnm->frame++;
+ CLHNM_SelectBuffers(hnm);
+ CLHNM_DecompUBA(hnm->new_frame_buffer, hnm->new_frame_buffer, hnm->old_frame_buffer, hnm->data_ptr, hnm->header.width, h6);
+ if(!(h6 & 1))
+ CLHNM_Desentrelace(hnm);
+ else
+ {
+// if(hnm->header.width == 640)
+// CLBlitter_RawCopy640(hnm->new_frame_buffer, hnm->final_buffer, hnm->header.height);
+// else
+ memcpy(hnm->final_buffer, hnm->new_frame_buffer, hnm->header.width * hnm->header.height);
+ }
+ goto end_frame;
+ case BE16('sd'):
+ case BE16('SD'):
+ if(use_sound)
+ {
+ if(!h6)
+ {
+ int sound_size = sz - 8;
+ if(!use_adpcm)
+ {
+ CLSoundGroup_SetDatas(soundGroup, hnm->data_ptr, sound_size - 2, 0);
+ if(sound_started)
+ CLSoundGroup_PlayNextSample(soundGroup, soundChannel);
+ else
+ pending_sounds++;
+ }
+ else
+ {
+ short *sound_buffer = (short*)CLSoundGroup_GetNextBuffer(soundGroup_adpcm);
+ if(!pending_sounds)
+ {
+ const int kDecompTableSize = 256 * sizeof(short);
+ CLHNM_LoadDecompTable((short*)hnm->data_ptr);
+ CLHNM_DecompADPCM(hnm->data_ptr + kDecompTableSize, sound_buffer, sound_size - kDecompTableSize);
+ CLSoundGroup_AssignDatas(soundGroup_adpcm, sound_buffer, (sound_size - kDecompTableSize) * 2, 0);
+ }
+ else
+ {
+ CLHNM_DecompADPCM(hnm->data_ptr, sound_buffer, sound_size);
+ CLSoundGroup_AssignDatas(soundGroup_adpcm, sound_buffer, sound_size * 2, 0);
+ }
+ pending_sounds++;
+ if(sound_started)
+ CLSoundGroup_PlayNextSample(soundGroup_adpcm, soundChannel);
+ }
+ }
+ else
+ {
+ __libError = -3;
+ __osError = 0;
+ CLCheckError();
+ }
+ }
+ hnm->data_ptr += sz - 8;
+ break;
+ default:
+ if(custom_chunk_handler)
+ custom_chunk_handler(hnm->data_ptr, sz - 8, id, h6, h7);
+ hnm->data_ptr += sz - 8;
+ }
+ }
+end_frame:;
+ if(use_preload)
+ {
+ }
+ return 1;
+}
+
+void CLHNM_ReadHeader(hnm_t *hnm)
+{
+ CLBeginCheck;
+ if(!use_preload)
+ {
+ long size = sizeof(hnm->header);
+ CLFile_Read(*hnm->file, &hnm->header, &size);
+ }
+ else
+ ;
+ CLCheckError();
+ CLEndCheck;
+ hnm->header.width = LE16(hnm->header.width);
+ hnm->header.height = LE16(hnm->header.height);
+ hnm->header.filesize = LE32(hnm->header.filesize);
+ hnm->header.nframe = LE32(hnm->header.nframe);
+ hnm->header.table_offset = LE32(hnm->header.table_offset);
+ hnm->header.speed = LE16(hnm->header.speed);
+ hnm->header.maxbuffer = LE16(hnm->header.maxbuffer);
+ hnm->header.buffersize = LE32(hnm->header.buffersize);
+ hnm->header.ff_20 = LE16(hnm->header.ff_20);
+ hnm->header.buffersize += 4096; //TODO: checkme
+}
+
+short CLHNM_GetVersion(hnm_t *hnm)
+{
+ CLNoError;
+ if(hnm->header.id == BE32('HNM4'))
+ return 4;
+ return -1;
+}
+
+int CLHNM_GetFrameNum(hnm_t *hnm)
+{
+ return hnm->frame;
+}
+
+void CLHNM_DeactivatePreloadBuffer()
+{
+ use_preload = 0;
+}
+
+void CLHNM_Prepare2Read(hnm_t *hnm, int mode)
+{
+ if(use_preload)
+ {
+ }
+}
+
+void CLHNM_SetPosIntoFile(hnm_t *hnm, long pos)
+{
+ CLFile_SetPosition(*hnm->file, 1, pos);
+}
+
+void CLHNM_Desentrelace320(unsigned char *frame_buffer, unsigned char *final_buffer, unsigned short height)
+{
+ unsigned int *input = (unsigned int*)frame_buffer;
+ unsigned int *line0 = (unsigned int*)final_buffer;
+ unsigned int *line1 = (unsigned int*)(final_buffer + 320);
+ int count = (height) / 2;
+ while(count--)
+ {
+ short i;
+ for(i = 0;i < 320 / 4;i++)
+ {
+ unsigned int p0 = *input++;
+ unsigned int p4 = *input++;
+#if 0
+ *line0++ = ((p4 & 0xFF00) >> 8) | ((p4 & 0xFF000000) >> 16) | ((p0 & 0xFF00) << 8) | (p0 & 0xFF000000);
+// *line0++ = (p0 & 0xFF000000) | ((p0 & 0xFF00) << 8) | ((p4 & 0xFF000000) >> 16) | ((p4 & 0xFF00) >> 8);
+ *line1++ = ((p0 & 0xFF0000) << 8) | ((p0 & 0xFF) << 16) | ((p4 & 0xFF0000) >> 8) | (p4 & 0xFF);
+#else
+ *line0++ = (p0 & 0xFF) | ((p0 & 0xFF0000) >> 8) | ((p4 & 0xFF) << 16) | ((p4 & 0xFF0000) << 8);
+ *line1++ = ((p0 & 0xFF00) >> 8) | ((p0 & 0xFF000000) >> 16) | ((p4 & 0xFF00) << 8) | (p4 & 0xFF000000);
+#endif
+ }
+ line0 += 320 / 4;
+ line1 += 320 / 4;
+ }
+}
diff --git a/engines/cryo/CLSouNdRaw.c b/engines/cryo/CLSouNdRaw.c
new file mode 100644
index 0000000000..22bc908307
--- /dev/null
+++ b/engines/cryo/CLSouNdRaw.c
@@ -0,0 +1,57 @@
+#include "cryolib.h"
+
+sound_t* CLSoundRaw_New(short arg1, float rate, short sampleSize, short mode)
+{
+ sound_t *sound;
+ CLBeginCheck;
+
+ sound = (sound_t*)CLMemory_Alloc(sizeof(*sound));
+ if(sound)
+ {
+ sound->ff_1A = arg1;
+ sound->rate = rate;
+ sound->sampleSize = sampleSize;
+ sound->buffer = 0;
+// sound->sndHandle = CLMemory_AllocHandle(arg1 + 100);
+// if(!sound->sndHandle)
+// {
+// __libError = -1;
+// __osError = MemError();
+// CLCheckError();
+// }
+// else
+ {
+ CLSound_PrepareSample(sound, mode);
+ CLNoError;
+ }
+ }
+ else
+ {
+ __libError = -1;
+ __osError = MemError();
+ CLCheckError();
+ }
+
+ CLEndCheck;
+ return sound;
+}
+
+void CLSoundRaw_Free(sound_t *sound)
+{
+ while(sound->locked) ;
+// CLMemory_FreeHandle(sound->sndHandle);
+ CLMemory_Free(sound);
+}
+
+void CLSoundRaw_AssignBuffer(sound_t *sound, void *buffer, int bufferOffs, int length)
+{
+ char *buf;
+ CLSound_SetLength(sound, length);
+ sound->length = length;
+ buf = bufferOffs + (char*)buffer;
+// if(CLSound_GetWantsDesigned())
+// CLSound_Signed2NonSigned(buf, length);
+ sound->buffer = buf;
+// if(sound->reversed && sound->sampleSize == 16)
+// ReverseBlock16(buf, length);
+}
diff --git a/engines/cryo/CryoLib.h b/engines/cryo/CryoLib.h
new file mode 100644
index 0000000000..5fe3e8cd63
--- /dev/null
+++ b/engines/cryo/CryoLib.h
@@ -0,0 +1,181 @@
+#pragma once
+#define SW16(n) ( (((n) & 0xFF) << 8) | (((n) >> 8) & 0xFF) )
+#define SW32(n) ( (((n) & 0xFF) << 24) | (((n) >> 24) & 0xFF) | (((n) & 0xFF00) << 8) | (((n) >> 8) & 0xFF00))
+#if 0
+//big-endian host
+#define LE16(n) SW16(n)
+#define LE32(n) SW32(n)
+#define BE16(n) (n)
+#define BE32(n) (n)
+#else
+//little-endian host
+#define LE16(n) (n)
+#define LE32(n) (n)
+#define BE16(n) SW16(n)
+#define BE32(n) SW32(n)
+#endif
+#define PLE16(p) ( (((unsigned char*)(p))[1] << 8) | ((unsigned char*)(p))[0] )
+#define PLE32(p) ( (((unsigned char*)(p))[3] << 24) | (((unsigned char*)(p))[2] << 16) | (((unsigned char*)(p))[1] << 8) | ((unsigned char*)(p))[0] )
+
+#include "audio/mixer.h"
+
+typedef void *SndChannel;
+typedef char *Handle;
+enum {
+ fsFromStart = 1
+};
+
+extern short __debug2;
+
+extern short __debug, __libError, __osError;
+
+#define CLBeginCheck { short __oldDebug = __debug; __debug = -1;
+#define CLEndCheck __debug = __oldDebug; }
+#define CLNoError __libError = 0;
+
+#define CLCheckError() if(__debug && __libError){ \
+ char buffer[260]; \
+ sprintf(buffer, "File %s at line %d, with __libError = %d and __osError = %d", __FILE__, __LINE__, __libError, __osError); \
+ DebugStr(c2pstr(buffer)); \
+ };
+
+#define CLAssert(x) if(!(x)) { \
+ char buffer[260]; \
+ sprintf(buffer, "File %s at line %d, with __libError = %d and __osError = %d", __FILE__, __LINE__, __libError, __osError); \
+ DebugStr(c2pstr(buffer)); \
+ };
+
+struct rect_t {
+int sy, sx, ey, ex;
+};
+typedef struct rect_t rect_t;
+
+struct view_t {
+unsigned char *p_buffer;
+int width;
+int height;
+short pitch;
+short doubled;
+short allocated;
+struct {
+int src_left;
+int src_top;
+int dst_left;
+int dst_top;
+int width;
+int height;
+} norm, zoom;
+};
+typedef struct view_t view_t;
+
+struct color3_t {
+short r, g, b;
+};
+typedef struct color3_t color3_t;
+
+struct color_t {
+short a, r, g, b;
+};
+typedef struct color_t color_t;
+
+struct palette_t {
+color_t colors[256];
+};
+typedef struct palette_t palette_t;
+
+#pragma pack(push, 1)
+struct hnmheader_t {
+int id;
+char flag1;
+char flag2;
+char reseverd;
+char bpp;
+unsigned short width;
+unsigned short height;
+int filesize;
+int nframe;
+int table_offset;
+short speed;
+short maxbuffer;
+int buffersize;
+short ff_20;
+char reserved2[14];
+char copyright[16];
+};
+typedef struct hnmheader_t hnmheader_t;
+#pragma pack(pop)
+
+struct hnm_t {
+int frame;
+int ff_4;
+file_t* file;
+hnmheader_t header;
+unsigned char *work_buffer[2];
+unsigned char *final_buffer;
+unsigned char *new_frame_buffer;
+unsigned char *old_frame_buffer;
+unsigned char *read_buffer;
+unsigned char *data_ptr;
+color_t palette[256];
+
+short can_loop;
+
+short ff_896;
+short chunk_id;
+int total_read;
+};
+typedef struct hnm_t hnm_t;
+
+//struct filespec_t {
+//char puff;
+//};
+
+struct sound_t {
+Handle sndHandle;
+short headerLen;
+long headerOffset;
+short ff_A;
+
+char *buffer;
+int ff_16;
+short ff_1A;
+float rate;
+short sampleSize;
+int length;
+short mode;
+volatile short locked;
+long loopStart;
+short loopTimes;
+short reversed;
+short ff_32;
+short volume;
+};
+typedef struct sound_t sound_t;
+
+#define CL_MAX_SOUNDS 64
+
+struct soundgroup_t {
+sound_t *sound[CL_MAX_SOUNDS];
+short numSounds;
+short soundIndex;
+short playIndex;
+short ff_106;
+};
+typedef struct soundgroup_t soundgroup_t;
+
+#define CL_MAX_CH_SOUNDS 10
+
+struct soundchannel_t {
+Audio::SoundHandle ch;
+int xx;
+
+short volumeLeft;
+short volumeRight;
+short numSounds;
+
+sound_t *sounds[CL_MAX_CH_SOUNDS];
+
+short ff_536;
+};
+typedef struct soundchannel_t soundchannel_t;
+
diff --git a/engines/cryo/CryoLibStub.c b/engines/cryo/CryoLibStub.c
new file mode 100644
index 0000000000..cabf2b597a
--- /dev/null
+++ b/engines/cryo/CryoLibStub.c
@@ -0,0 +1,604 @@
+
+ ///// Mac APIs
+ typedef short OSErr;
+
+ short MemError()
+ {
+ return 0;
+ }
+
+ void SysBeep(int x)
+ {
+ }
+
+ OSErr SetFPos(short handle, short mode, long pos)
+ {
+ return 0;
+ }
+
+ OSErr FSRead(short handle, long *size, void *buffer)
+ {
+ return 0;
+ }
+
+ void FlushEvents(short arg1, short arg2)
+ {
+ }
+
+ char* c2pstr(char *s)
+ {
+ return s;
+ }
+
+ void DebugStr(char *s)
+ {
+ }
+
+ // from mw lib???
+ long TickCount()
+ {
+ return g_system->getMillis();
+ }
+
+ ///// CLMemory
+ void* CLMemory_Alloc(int size)
+ {
+ return malloc(size);
+ }
+ void CLMemory_Free(void *ptr)
+ {
+ //TODO: due to a bug in ssndfl() sometimes a null ptr passed, skip it
+ if (!ptr)
+ return;
+
+ free(ptr);
+ }
+
+
+ ///// CLTimer
+ volatile long TimerTicks = 0; // incremented in realtime
+
+ ///// CLView
+ void CLView_SetSrcZoomValues(view_t *view, int x, int y)
+ {
+ view->zoom.src_left = x;
+ view->zoom.src_top = y;
+ }
+ void CLView_SetDisplayZoomValues(view_t *view, int w, int h)
+ {
+ view->zoom.width = w;
+ view->zoom.height = h;
+ }
+ void CLView_Free(view_t *view)
+ {
+ if (view->p_buffer && view->allocated)
+ CLMemory_Free(view->p_buffer);
+ if (view)
+ CLMemory_Free(view);
+ }
+ void CLView_InitDatas(view_t *view, int w, int h, void *buffer)
+ {
+ view->p_buffer = (unsigned char*)buffer;
+ view->width = w;
+ view->height = h;
+ view->pitch = w;
+ view->doubled = 0;
+ view->norm.src_left = 0;
+ view->norm.src_top = 0;
+ view->norm.dst_left = 0;
+ view->norm.dst_top = 0;
+ view->norm.width = w;
+ view->norm.height = h;
+ view->zoom.src_left = 0;
+ view->zoom.src_top = 0;
+ view->zoom.dst_left = 0;
+ view->zoom.dst_top = 0;
+ view->zoom.width = w;
+ view->zoom.height = h;
+ }
+ view_t* CLView_New(int w, int h)
+ {
+ view_t *view = (view_t*)CLMemory_Alloc(sizeof(view_t));
+ if (view)
+ {
+ void *buffer = (unsigned char*)CLMemory_Alloc(w * h);
+ if (buffer)
+ {
+ view->allocated = 1;
+ CLView_InitDatas(view, w, h, buffer);
+ }
+ else
+ {
+ CLMemory_Free(view);
+ view = 0;
+ }
+ }
+ return view;
+ }
+ void CLView_CenterIn(view_t *parent, view_t *child)
+ {
+ child->norm.dst_left = (parent->width - child->norm.width) / 2;
+ child->norm.dst_top = (parent->height - child->norm.height) / 2;
+ child->zoom.dst_left = (parent->width - child->zoom.width) / 2;
+ child->zoom.dst_top = (parent->height - child->zoom.height) / 2;
+ }
+
+ ///// CLScreenView
+ view_t ScreenView;
+
+ void CLScreenView_Init()
+ {
+ // ScreenView is the game's target screen (a pc display)
+ // we use a dedicated surface for it, which at some point will be
+ // presented to user by System::copyRectToScreen call
+ CLView_InitDatas(&ScreenView, g_ed->_screen.w, g_ed->_screen.h, g_ed->_screen.getPixels());
+ }
+
+ void CLScreenView_CenterIn(view_t *view)
+ {
+ CLView_CenterIn(&ScreenView, view);
+ }
+
+ ///// CLPalette
+ unsigned short gIntervalLast, gIntervalFirst, gIntervalSet;
+ short gMacintize = 0;
+ color_t black_palette[256];
+ color_t last_palette[256];
+ void CLPalette_Init()
+ {
+ short i;
+ for (i = 0; i < 256; i++)
+ black_palette[i].r = black_palette[i].g = black_palette[i].b = 0;
+ }
+ void CLPalette_SetLastPalette(color_t *palette, short first, short count)
+ {
+ short i;
+ for (i = first; i < first + count; i++)
+ last_palette[i] = palette[i];
+ }
+ void CLPalette_GetLastPalette(color_t *palette)
+ {
+ short i;
+ for (i = 0; i < 256; i++)
+ palette[i] = last_palette[i];
+ }
+ void CLPalette_SetRGBColor(color_t *palette, unsigned short index, color3_t *rgb)
+ {
+ palette[index].r = rgb->r;
+ palette[index].g = rgb->g;
+ palette[index].b = rgb->b;
+ palette[index].a = 0;
+ }
+ void CLPalette_Macintize(short macintize)
+ {
+ gMacintize = macintize;
+ }
+ void CLPalette_SetInterval(unsigned short first, unsigned short last)
+ {
+ gIntervalFirst = first;
+ gIntervalSet = 1;
+ gIntervalLast = last;
+ }
+ void CLPalette_DeactivateInterval()
+ {
+ gIntervalSet = 0;
+ }
+ void CLPalette_Send2Screen(struct color_t *palette, unsigned short first, unsigned short count)
+ {
+ OSErr err;
+ short i;
+ if (gMacintize)
+ {
+ palette[0].r = palette[0].g = palette[0].b = 0xFFFF;
+ palette[255].r = palette[255].g = palette[255].b = 0;
+ }
+ if (gIntervalSet)
+ {
+ if (first < gIntervalFirst)
+ first = gIntervalFirst;
+ if (first + count > gIntervalLast)
+ count = gIntervalLast - first;
+ }
+
+ byte buffer[256 * 3];
+ for (i = 0; i < 256; i++)
+ {
+ buffer[i * 3] = palette[i].r >> 8;
+ buffer[i * 3 + 1] = palette[i].g >> 8;
+ buffer[i * 3 + 2] = palette[i].b >> 8;
+ }
+
+ g_system->getPaletteManager()->setPalette(buffer, first, count);
+ g_system->updateScreen();
+
+ CLPalette_SetLastPalette(palette, first, count);
+ }
+ void CLPalette_BeBlack()
+ {
+ CLPalette_Send2Screen(black_palette, 0, 256);
+ }
+ void CLPalette_BeSystem()
+ {
+ }
+
+ ///// CLBlitter
+ static unsigned short newPaletteCount, newPaletteFirst;
+ static color_t *pNewPalette;
+ static unsigned short useNewPalette;
+
+ void CLBlitter_CopyViewRect(view_t *view1, view_t *view2, rect_t *rect1, rect_t *rect2)
+ {
+ int sy, dy = rect2->sy, x, w = rect1->ex - rect1->sx + 1;
+ // debug("- Copy rect %3d:%3d-%3d:%3d -> %3d:%3d-%3d:%3d - %s",
+ // rect1->sx, rect1->sy, rect1->ex, rect1->ey,
+ // rect2->sx, rect2->sy, rect2->ex, rect2->ey,
+ // (rect1->ex - rect1->sx == rect2->ex - rect2->sx && rect1->ey - rect1->sy == rect2->ey - rect2->sy) ? "ok" : "BAD");
+ assert(rect1->ex - rect1->sx == rect2->ex - rect2->sx && rect1->ey - rect1->sy == rect2->ey - rect2->sy);
+ for (sy = rect1->sy; sy <= rect1->ey; sy++, dy++)
+ {
+ unsigned char *s = view1->p_buffer + sy * view1->pitch + rect1->sx;
+ unsigned char *d = view2->p_buffer + dy * view2->pitch + rect2->sx;
+ for (x = 0; x < w; x++)
+ *d++ = *s++;
+ }
+ }
+ void CLBlitter_Send2ScreenNextCopy(color_t *palette, unsigned short first, unsigned short count)
+ {
+ pNewPalette = palette;
+ useNewPalette = 1;
+ newPaletteFirst = first;
+ newPaletteCount = count;
+ }
+ void CLBlitter_OneBlackFlash()
+ {
+ }
+ void CLBlitter_CopyView2ViewSimpleSize(unsigned char *src, short srcw, short srcp, short srch,
+ unsigned char *dst, short dstw, short dstp, short dsth)
+ {
+ short x, y;
+ for (y = 0; y < srch; y++)
+ {
+ for (x = 0; x < srcw; x++)
+ *dst++ = *src++;
+ src += srcp - srcw;
+ dst += dstp - dstw;
+ }
+ }
+ void CLBlitter_CopyView2ScreenCUSTOM(view_t *view)
+ {
+ view_t *dest = &ScreenView;
+ if (!view->doubled)
+ {
+ short srcpitch = view->pitch;
+ short dstpitch = dest->pitch;
+
+ // this is not quite correct?
+ // CLBlitter_CopyView2ViewSimpleSize(view->p_buffer + view->norm.src_top * srcpitch + view->norm.src_left, view->norm.width, srcpitch, view->norm.height,
+ // dest->p_buffer + dest->norm.dst_top * dstpitch + dest->norm.dst_left, dest->norm.width, dstpitch, dest->norm.height);
+
+ CLBlitter_CopyView2ViewSimpleSize(view->p_buffer + view->norm.src_top * srcpitch + view->norm.src_left, view->norm.width, srcpitch, view->norm.height,
+ dest->p_buffer + (dest->norm.dst_top + view->norm.dst_top) * dstpitch + dest->norm.dst_left + view->norm.dst_left, dest->norm.width, dstpitch, dest->norm.height);
+
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+ void CLBlitter_CopyView2Screen(view_t *view)
+ {
+
+ if (useNewPalette)
+ {
+ color_t palette[256];
+ CLPalette_GetLastPalette(palette);
+ CLPalette_Send2Screen(pNewPalette, newPaletteFirst, newPaletteCount);
+ useNewPalette = 0;
+ }
+
+ //TODO: quick hack to force screen update
+ if (view)
+ CLBlitter_CopyView2ScreenCUSTOM(view);
+
+ g_system->copyRectToScreen(ScreenView.p_buffer, ScreenView.pitch, 0, 0, ScreenView.width, ScreenView.height);
+ g_system->updateScreen();
+ }
+ void CLBlitter_UpdateScreen()
+ {
+ CLBlitter_CopyView2Screen(nullptr);
+ }
+ void CLBlitter_FillView(view_t *view, unsigned int fill)
+ {
+ short x, y;
+ unsigned char *d = view->p_buffer;
+ assert((fill & 0xFF) * 0x01010101 == fill);
+ for (y = 0; y < view->height; y++)
+ {
+ for (x = 0; x < view->width; x++)
+ *d++ = fill;
+ d += view->pitch - view->width;
+ }
+ }
+ void CLBlitter_FillScreenView(unsigned int fill)
+ {
+ CLBlitter_FillView(&ScreenView, fill);
+ }
+
+
+ ///// events wrapper
+ int _mouseButton;
+ byte _keyState[256];
+
+ void pollEvents()
+ {
+ g_system->delayMillis(10);
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ // Handle keypress
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ return;
+
+ case Common::EVENT_KEYDOWN:
+ // _keyState[(byte)toupper(event.kbd.ascii)] = true;
+ return;
+ case Common::EVENT_KEYUP:
+ // _keyState[(byte)toupper(event.kbd.ascii)] = false;
+ return;
+ case Common::EVENT_LBUTTONDOWN:
+ _mouseButton = 1;
+ return;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButton = 2;
+ return;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ _mouseButton = 0;
+ return;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ ///// CLKeyboard
+ short CLKeyboard_HasCmdDown()
+ {
+ return 0;
+ }
+ void CLKeyboard_Read()
+ {
+ pollEvents();
+ }
+ unsigned char CLKeyboard_GetLastASCII()
+ {
+ return 0;
+ }
+ short CLKeyboard_IsScanCodeDown(short scancode)
+ {
+ return 0;
+ }
+
+ ///// CLMouse
+ void CLMouse_Hide()
+ {
+ }
+ void CLMouse_Show()
+ {
+ }
+ void CLMouse_GetPosition(short *x, short *y)
+ {
+ *x = g_system->getEventManager()->getMousePos().x;
+ *y = g_system->getEventManager()->getMousePos().y;
+ }
+ void CLMouse_SetPosition(short x, short y)
+ {
+ g_system->warpMouse(x, y);
+ }
+ unsigned short CLMouse_IsDown()
+ {
+ pollEvents();
+ return _mouseButton != 0;
+ }
+
+ ///// CLFile
+ void CLFile_SetFilter(int a3, int a4, int a5, int a6, int a7)
+ {
+ }
+ void CLFile_SetFinderInfos(void *fs, int a4, int a5)
+ {
+ }
+ void CLFile_GetFullPath(void *a3, char *a4)
+ {
+ }
+ void CLFile_MakeStruct(int a3, int a4, char *name, filespec_t *fs)
+ {
+ strcpy(fs->name, name);
+ fs->create = 0;
+ }
+ void CLFile_Create(filespec_t *fs)
+ {
+ fs->create = 1;
+ }
+ void CLFile_Open(filespec_t *fs, short mode, file_t& handle)
+ {
+ handle.open(fs->name);
+ }
+ void CLFile_Close(file_t& handle)
+ {
+ handle.close();
+ }
+ void CLFile_SetPosition(file_t& handle, short mode, long pos)
+ {
+ assert(mode == 1);
+ handle.seek(pos, 0);
+ }
+ void CLFile_Read(file_t& handle, void *buffer, long *size)
+ {
+ handle.read(buffer, *size);
+ }
+ void CLFile_Write(file_t& handle, void *buffer, long *size)
+ {
+ assert(0);
+ }
+
+ ///// CLSound
+ // base sound
+ void CLSound_PrepareSample(sound_t *sound, short mode)
+ {
+ sound->mode = mode;
+ sound->locked = 0;
+ sound->loopTimes = 0;
+ sound->reversed = 0;
+ sound->ff_32 = 0;
+ sound->volume = 255;
+ }
+ void CLSound_SetWantsDesigned(short designed)
+ {
+ }
+ void CLSound_SetLength(sound_t *sound, int length)
+ {
+ }
+
+ ///// CLSoundRaw
+ // sound from memory buffer
+#include "CLSouNdRaw.c"
+
+ ///// CLSoundChannel
+ /// sound output device that plays queue of sounds
+ soundchannel_t* CLSoundChannel_New(int arg1)
+ {
+ short i;
+ soundchannel_t *ch = (soundchannel_t*)CLMemory_Alloc(sizeof(*ch));
+ if (!ch)
+ return 0;
+
+ ch->volumeLeft = ch->volumeRight = 255;
+ ch->numSounds = 0;
+
+ for (i = 0; i < CL_MAX_CH_SOUNDS; i++)
+ ch->sounds[i] = 0;
+
+ return ch;
+ }
+ void CLSoundChannel_Free(soundchannel_t *ch)
+ {
+ CLMemory_Free(ch);
+ }
+ void CLSoundChannel_Stop(soundchannel_t *ch)
+ {
+ // g_ed->_mixer->stopHandle(ch->ch);
+ }
+ void CLSoundChannel_Play(soundchannel_t *ch, sound_t *sound)
+ {
+ }
+ short CLSoundChannel_GetVolume(soundchannel_t *ch)
+ {
+ return (ch->volumeLeft + ch->volumeRight) / 2;
+ }
+ void CLSoundChannel_SetVolume(soundchannel_t *ch, short volume)
+ {
+ if (volume < 0 || volume > 255)
+ return;
+ ch->volumeLeft = volume;
+ ch->volumeRight = volume;
+ }
+ void CLSoundChannel_SetVolumeRight(soundchannel_t *ch, short volume)
+ {
+ if (volume < 0 || volume > 255)
+ return;
+ ch->volumeRight = volume;
+ }
+ void CLSoundChannel_SetVolumeLeft(soundchannel_t *ch, short volume)
+ {
+ if (volume < 0 || volume > 255)
+ return;
+ ch->volumeLeft = volume;
+ }
+
+ ///// CLSoundGroup
+ /// a queue of sounds of same format
+#include "CLSoundGroup.c"
+
+ ///// CLTimer
+ void CLTimer_Action(void *arg)
+ {
+ // long& counter = *((long*)arg);
+ // counter++;
+ TimerTicks++;
+ }
+
+ void CLTimer_Init()
+ {
+ g_system->getTimerManager()->installTimerProc(CLTimer_Action, 10000, nullptr, "100hz timer");
+ }
+
+ void CLTimer_Done()
+ {
+ g_system->getTimerManager()->removeTimerProc(CLTimer_Action);
+ }
+
+ ///// CRYOLib
+ void CRYOLib_InstallExitPatch()
+ {
+ }
+ void CRYOLib_RemoveExitPatch()
+ {
+ }
+ void CRYOLib_Init()
+ {
+ }
+ void CRYOLib_Done()
+ {
+ }
+ void CRYOLib_MinimalInit()
+ {
+ }
+ void CRYOLib_ManagersInit()
+ {
+ CLTimer_Init();
+ CLScreenView_Init();
+ }
+ void CRYOLib_ManagersDone()
+ {
+ CLTimer_Done();
+ }
+ void CRYOLib_SetDebugMode(short enable)
+ {
+ }
+ void CRYOLib_InstallEmergencyExit(void(*proc)())
+ {
+ }
+ void CRYOLib_SetupEnvironment()
+ {
+ }
+ void CRYOLib_RestoreEnvironment()
+ {
+ }
+ void CRYOLib_TestConfig()
+ {
+ }
+
+ ///// CLComputer
+ short CLComputer_Has68030()
+ {
+ return 0;
+ }
+ short CLComputer_Has68040()
+ {
+ return 0;
+ }
+
+ ///// CLDesktop
+ void CLDesktop_TestOpenFileAtStartup()
+ {
+ }
+
+ ///// CLHNM
+#include "CLHNM.c"
+
+ ///// CLError
+#include "CLError.c"
diff --git a/engines/cryo/LempelZiv.cpp b/engines/cryo/LempelZiv.cpp
new file mode 100644
index 0000000000..6020c96e12
--- /dev/null
+++ b/engines/cryo/LempelZiv.cpp
@@ -0,0 +1,7 @@
+#include "LempelZiv.h"
+
+namespace Cryo {
+
+
+
+} \ No newline at end of file
diff --git a/engines/cryo/LempelZiv.h b/engines/cryo/LempelZiv.h
new file mode 100644
index 0000000000..636d7af148
--- /dev/null
+++ b/engines/cryo/LempelZiv.h
@@ -0,0 +1,102 @@
+#pragma once
+
+namespace Cryo {
+
+ class BitReaderBase {
+ public:
+ unsigned char *_data; //NB! never override this - used by decompressor
+ unsigned int _queue;
+ unsigned int _queueLeft;
+ public:
+ BitReaderBase(void *data, unsigned int dataSize = 0)
+ {
+ _data = static_cast<unsigned char*>(data);
+ _queue = _queueLeft = 0;
+ }
+
+ unsigned char GetBit()
+ {
+ return 0; // to be overriden
+ }
+ };
+
+ // used to decompress HSQ files
+ class BitReader16 : BitReaderBase {
+ public:
+ unsigned char GetBit()
+ {
+ if (!_queueLeft)
+ {
+ _queue = (_data[1] << 8) | _data[0];
+ _data += 2;
+ _queueLeft += 16;
+ }
+ unsigned char bit = _queue & 1;
+ _queue >>= 1;
+ _queueLeft--;
+ return bit;
+ }
+ };
+
+ // used by HNM decoder
+ class BitReader32 : BitReaderBase {
+ public:
+ unsigned char GetBit()
+ {
+ if (!_queueLeft)
+ {
+ _queue = (_data[3] << 24) | (_data[2] << 16) | (_data[1] << 8) | _data[0];
+ _data += 4;
+ _queueLeft += 32;
+ }
+ unsigned char bit = (_queue >> (_queueLeft - 1)) & 1;
+ _queueLeft--;
+ return bit;
+ }
+ };
+
+ template <class BitReader>
+ class LempelZivBase : BitReader
+ {
+ public:
+ LempelZivBase(void *input, unsigned int inputSize) : BitReader(input, inputSize)
+
+ unsigned int UnpackBuffer(void *output, unsigned int maxOutputSize)
+ {
+ unsigned char *out = static_cast<unsigned char*>(output);
+ for (;;)
+ {
+ if (GetBit())
+ {
+ *out++ = *_data++;
+ }
+ else
+ {
+ int length, offset;
+ if (GetBit())
+ {
+ length = *_data & 7;
+ offset = ((_data[1] << 8) | _data[0]) >> 3; _data += 2;
+ offset -= 8192;
+ if (!length)
+ length = *_data++;
+ if (!length)
+ break;
+ }
+ else
+ {
+ length = GetBit() * 2 + GetBit();
+ offset = *(_data++) - 256;
+ }
+ length += 2;
+ while (length--)
+ {
+ *out = *(out + offset); out++;
+ }
+ }
+ }
+ return out - static_cast<unsigned char*>(output);
+ }
+ };
+
+} \ No newline at end of file
diff --git a/engines/cryo/ResourceManager.cpp b/engines/cryo/ResourceManager.cpp
new file mode 100644
index 0000000000..72804438c5
--- /dev/null
+++ b/engines/cryo/ResourceManager.cpp
@@ -0,0 +1,116 @@
+#include "ResourceManager.h"
+
+namespace Cryo {
+
+ ResourceManager::ResourceManager()
+ {
+ }
+
+ ResourceManager::ResourceManager(const Common::String &datFileName)
+ {
+ LoadDatFile(datFileName);
+ }
+
+ ResourceManager::~ResourceManager()
+ {
+ }
+
+ bool ResourceManager::LoadDatFile(const Common::String &datFileName)
+ {
+ if (_datFile.isOpen())
+ {
+ _datFile.close();
+ _files.clear();
+ }
+
+ assert(_datFile.open(datFileName));
+
+ unsigned short numFiles = _datFile.readUint16LE();
+
+ for (unsigned short i = 0; i < numFiles; i++)
+ {
+ DatFileEntry entry;
+
+ _datFile.read(entry._name, sizeof(entry._name));
+ entry._size = _datFile.readUint32LE();
+ entry._offset = _datFile.readUint32LE();
+ entry._flag = _datFile.readByte();
+
+ _files.push_back(entry);
+ }
+
+ return true;
+ }
+
+ Common::SeekableReadStream *ResourceManager::GetFile(const Common::String &resName, unsigned int hintIndex)
+ {
+ // First, try raw disk file so we can support modding/patching
+
+ if (Common::File::exists(resName))
+ {
+ debug("Loading %s from disk", resName);
+
+ Common::File *resource = new Common::File();
+ resource->open(resName);
+ return resource;
+ }
+
+ // Look inside .dat file
+
+ if (_datFile.isOpen())
+ {
+ for (unsigned int i = hintIndex; i < _files.size(); i++)
+ {
+ if (!resName.compareToIgnoreCase(_files[i]._name))
+ {
+ debug("Loading %s from dat file", resName);
+ Common::SeekableSubReadStream *resource = new Common::SeekableSubReadStream(&_datFile, _files[i]._offset, _files[i]._offset + _files[i]._size);
+ return resource;
+ }
+ }
+ }
+
+ debug("Unable to load %s - does't exists", resName);
+ return nullptr;
+ }
+
+ Common::SeekableReadStream *ResourceManager::GetFile(unsigned int resIndex)
+ {
+ if (_files.size() > resIndex)
+ {
+ return GetFile(Common::String(_files[resIndex]._name), resIndex);
+ }
+
+ return nullptr;
+ }
+
+ void *ResourceManager::StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size)
+ {
+ if (!stream)
+ return nullptr;
+
+ unsigned int readSize = stream->size();
+ unsigned char *data = new unsigned char[readSize + 1];
+ readSize = stream->read(data, readSize);
+
+ if (size)
+ *size = readSize;
+ return data;
+ }
+
+ void* ResourceManager::GetData(const Common::String &resName, unsigned int *size)
+ {
+ Common::SeekableReadStream *resource = GetFile(resName);
+ void *data = StreamToBuffer(resource, size);
+ delete resource;
+ return data;
+ }
+
+ void* ResourceManager::GetData(int resIndex, unsigned int *size)
+ {
+ Common::SeekableReadStream *resource = GetFile(resIndex);
+ void *data = StreamToBuffer(resource, size);
+ delete resource;
+ return data;
+ }
+} \ No newline at end of file
diff --git a/engines/cryo/ResourceManager.h b/engines/cryo/ResourceManager.h
new file mode 100644
index 0000000000..1ef577678b
--- /dev/null
+++ b/engines/cryo/ResourceManager.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/debug.h"
+
+namespace Cryo {
+
+ template<typename T>
+ class CryoArray {
+ private:
+ unsigned char *_data;
+ bool _ownData;
+ unsigned short ElementOffset(int num)
+ {
+ assert(_data && num < Count())
+ return (static_cast<unsigned short*>_data)[num];
+ }
+ public:
+ CryoArray(void* data, bool ownData) : _data(data), _ownData(ownData)
+ {
+ }
+ ~CryoArray()
+ {
+ if (_ownData)
+ delete data;
+ }
+ unsigned short Count()
+ {
+ return ElementOffset(0) / 2;
+ }
+ const T* operator[](int index)
+ {
+ return static_cast<T*>(_data + ElementOffset(num));
+ }
+ };
+
+ class ResourceManager
+ {
+ private:
+ struct DatFileEntry {
+ char _name[16];
+ unsigned int _size;
+ unsigned int _offset;
+ unsigned char _flag;
+ };
+
+ Common::Array<DatFileEntry> _files;
+ Common::File _datFile;
+
+ static void *StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size);
+
+ public:
+ ResourceManager(const Common::String &datFileName);
+ ResourceManager();
+ ~ResourceManager();
+
+ bool LoadDatFile(const Common::String &datFileName);
+
+ // Load resource as a seekable stream
+ Common::SeekableReadStream *GetFile(const Common::String &resName, unsigned int hintIndex = 0);
+ Common::SeekableReadStream *GetFile(unsigned int resIndex);
+
+ // Load resource as a buffer
+ void* GetData(const Common::String &resName, unsigned int *size = nullptr);
+ void* GetData(int resIndex, unsigned int *size = nullptr);
+ void* operator[](int resIndex)
+ {
+ return GetData(resIndex);
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/engines/cryo/bugs.txt b/engines/cryo/bugs.txt
new file mode 100644
index 0000000000..50b857e1d2
--- /dev/null
+++ b/engines/cryo/bugs.txt
@@ -0,0 +1,10 @@
+
+1. Open menu and replay last dialog, then press stop. hover over buttons - hint text will be misplaced
+2. During valley location change some junk appears in the bottom half of screen for a brief time (broken transition effect?)
+3. Transitions often show a lot of red colors (bad palette fadein/out?)
+4. After game load in some areas (White Arch) top bar and inventory not redrawn due to (DrawFlags?) initialized incorrectly
+5. Mac reload feature uses hardcoded savefile from eden.dat
+6. First time in Tau's cave, try to take knife. When Dina objects, click on her - Tau's dialog will start (maybe it's original bug?)
+7. Mouse clipping may be lost during FMV scenes
+8. Screen doubling feature probably doesn't work (not really needed, can be replaced with built-in SCUMMVM scaler)
+9. Tons of debug messages spam when hover mouse over party icons or menu buttons
diff --git a/engines/cryo/clsoundgroup.c b/engines/cryo/clsoundgroup.c
new file mode 100644
index 0000000000..ae347fcb58
--- /dev/null
+++ b/engines/cryo/clsoundgroup.c
@@ -0,0 +1,117 @@
+#include "cryolib.h"
+
+soundgroup_t* CLSoundGroup_New(short numSounds, short arg4, short sampleSize, float rate, short mode)
+{
+ soundgroup_t *sg;
+ short i;
+
+ sg = (soundgroup_t*)CLMemory_Alloc(sizeof(*sg));
+ if(numSounds < CL_MAX_SOUNDS)
+ sg->numSounds = numSounds;
+ else
+ {
+ __libError = -3;
+ __osError = 0;
+ CLCheckError();
+ sg->numSounds = CL_MAX_SOUNDS;
+ }
+ for(i = 0;i < sg->numSounds;i++)
+ {
+ sound_t *sound = CLSoundRaw_New(arg4, rate, sampleSize, mode);
+ sg->sound[i] = sound;
+ sound->ff_1A = arg4;
+ }
+ sg->soundIndex = 0;
+ sg->playIndex = 0;
+ sg->ff_106 = 1;
+
+ return sg;
+}
+
+void CLSoundGroup_Free(soundgroup_t *sg)
+{
+ short i;
+ for(i = 0;i < sg->numSounds;i++)
+ CLSoundRaw_Free(sg->sound[i]);
+ CLMemory_Free(sg);
+}
+
+void CLSoundGroup_Reverse16All(soundgroup_t *sg)
+{
+ short i;
+ for(i = 0;i < sg->numSounds;i++)
+ sg->sound[i]->reversed = 1;
+}
+
+void* CLSoundGroup_GetNextBuffer(soundgroup_t *sg)
+{
+ sound_t *sound = sg->sound[sg->soundIndex];
+ if(sg->ff_106)
+ while(sound->locked) ;
+ return ((char*)(*sound->sndHandle)) + sound->headerLen;
+}
+
+short CLSoundGroup_AssignDatas(soundgroup_t *sg, void *buffer, int length, short isSigned)
+{
+ sound_t *sound = sg->sound[sg->soundIndex];
+ if(sg->ff_106)
+ while(sound->locked) ;
+ else
+ if(sound->locked)
+ return 0;
+ sound->buffer = (char*)buffer;
+ CLSound_SetLength(sound, length);
+ sound->length = length;
+// if(sound->reversed && sound->sampleSize == 16)
+// ReverseBlock16(buffer, length);
+// if(isSigned)
+// CLSound_Signed2NonSigned(buffer, length);
+ if(sg->soundIndex == sg->numSounds - 1)
+ sg->soundIndex = 0;
+ else
+ sg->soundIndex++;
+
+ return 1;
+}
+
+short CLSoundGroup_SetDatas(soundgroup_t *sg, void *data, int length, short isSigned)
+{
+ void *buffer;
+ sound_t *sound = sg->sound[sg->soundIndex];
+ if(length >= sound->ff_1A)
+ {
+ __libError = -10;
+ __osError = 0;
+ CLCheckError();
+ }
+ if(sg->ff_106)
+ while(sound->locked) ;
+ else
+ if(sound->locked)
+ return 0;
+ buffer = ((char*)(*sound->sndHandle)) + sound->headerLen;
+ sound->buffer = (char*)buffer;
+ memcpy(buffer, data, length);
+ CLSound_SetLength(sound, length);
+ sound->length = length;
+// if(sound->reversed && sound->sampleSize == 16)
+// ReverseBlock16(buffer, length);
+// if(isSigned)
+// CLSound_Signed2NonSigned(buffer, length);
+ if(sg->soundIndex == sg->numSounds - 1)
+ sg->soundIndex = 0;
+ else
+ sg->soundIndex++;
+
+ return 1;
+}
+
+void CLSoundGroup_PlayNextSample(soundgroup_t *sg, soundchannel_t *ch)
+{
+ CLSoundChannel_Play(ch, sg->sound[sg->playIndex]);
+ if(sg->playIndex == sg->numSounds - 1)
+ sg->playIndex = 0;
+ else
+ sg->playIndex++;
+
+}
diff --git a/engines/cryo/configure.engine b/engines/cryo/configure.engine
new file mode 100644
index 0000000000..a0f5a044e9
--- /dev/null
+++ b/engines/cryo/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine cryo "Lost Eden" no "" "" ""
diff --git a/engines/cryo/cryo.cpp b/engines/cryo/cryo.cpp
new file mode 100644
index 0000000000..425b055f8e
--- /dev/null
+++ b/engines/cryo/cryo.cpp
@@ -0,0 +1,81 @@
+#include "common/scummsys.h"
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+#include "common/system.h"
+//#include "common/timer.h"
+
+#include "engines/util.h"
+
+#include "cryo/cryo.h"
+#include "cryo/eden.h"
+
+namespace Cryo {
+
+CryoEngine *g_ed = 0;
+
+CryoEngine::CryoEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _console(nullptr) {
+ // Put your engine in a sane state, but do nothing big yet;
+ // in particular, do not load data from files; rather, if you
+ // need to do such things, do them from run().
+
+ // Do not initialize graphics here
+ // Do not initialize audio devices here
+
+ // However this is the place to specify all default directories
+// const Common::FSNode gameDataDir(ConfMan.get("path"));
+// SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
+
+ // Here is the right place to set up the engine specific debug channels
+ DebugMan.addDebugChannel(kCryoDebugExample, "example", "this is just an example for a engine specific debug channel");
+ DebugMan.addDebugChannel(kCryoDebugExample2, "example2", "also an example");
+
+ // Don't forget to register your random source
+ _rnd = new Common::RandomSource("cryo");
+
+ debug("CryoEngine::CryoEngine");
+
+ g_ed = this;
+}
+
+CryoEngine::~CryoEngine() {
+ debug("CryoEngine::~CryoEngine");
+
+ // Dispose your resources here
+ delete _rnd;
+
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+}
+
+Common::Error CryoEngine::run() {
+ // Initialize graphics using following:
+ initGraphics(320, 200, false);
+ _screen.create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+
+ // Create debugger console. It requires GFX to be initialized
+ _console = new Console(this);
+
+ // Additional setup.
+ debug("CryoEngine::init");
+
+ // Your main even loop should be (invoked from) here.
+ debug("CryoEngine::go: Hello, World!");
+
+ // This test will show up if -d1 and --debugflags=example are specified on the commandline
+ debugC(1, kCryoDebugExample, "Example debug call");
+
+ // This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline
+ debugC(3, kCryoDebugExample | kCryoDebugExample2, "Example debug call two");
+
+ game.main();
+
+ return Common::kNoError;
+}
+
+} // End of namespace Cryo
diff --git a/engines/cryo/cryo.h b/engines/cryo/cryo.h
new file mode 100644
index 0000000000..010e9f01fe
--- /dev/null
+++ b/engines/cryo/cryo.h
@@ -0,0 +1,62 @@
+#ifndef CRYO_H
+#define CRYO_H
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/random.h"
+#include "engines/engine.h"
+#include "gui/debugger.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "cryo/eden.h"
+
+namespace Cryo {
+
+class Console;
+
+// our engine debug channels
+enum {
+ kCryoDebugExample = 1 << 0,
+ kCryoDebugExample2 = 1 << 1
+ // next new channel must be 1 << 2 (4)
+ // the current limitation is 32 debug channels (1 << 31 is the last one)
+};
+
+class CryoEngine : public Engine {
+public:
+ CryoEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ ~CryoEngine();
+
+ virtual Common::Error run();
+
+ // Detection related functions
+ const ADGameDescription *_gameDescription;
+ const char *getGameId() const;
+ Common::Platform getPlatform() const;
+
+ // We need random numbers
+ Common::RandomSource *_rnd;
+
+ Graphics::Surface _screen;
+ EdenGame game;
+
+private:
+ Console *_console;
+};
+
+extern CryoEngine *g_ed;
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(CryoEngine *vm) {}
+ virtual ~Console(void) {}
+};
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/defs.h b/engines/cryo/defs.h
new file mode 100644
index 0000000000..ff3642b162
--- /dev/null
+++ b/engines/cryo/defs.h
@@ -0,0 +1,1399 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include "cryolib.h"
+
+#define GetElem(array, idx) \
+ ( (char*)(array) + PLE16((idx) * 2 + (char*)(array)) )
+/*
+static inline void* AGetElem(unsigned char *arr, short index)
+{
+ unsigned char *p = arr + num * 2;
+ unsigned char o0 = *p++;
+ unsigned char o1 = *p++;
+ unsigned short ofs = (o1 << 8) | o0;
+ return arr + ofs;
+}
+*/
+
+///////////////// Game defs
+
+#define FONT_HEIGHT 9
+
+
+/*
+Glossary
+ room - a single game world's screen. referenced by 16-bit number 0xAALL, where AA - area# and LL - location#
+ area - geographic area - Mo, Chamaar, etc
+ location - coordinates of particular room in an area. usually in form of 0xXY, where X - map row, Y - map column
+ character - an unique character (human or dino.) Has their own voice/dialog lines
+ person - instance of a character. Usually tied to specific room, but some may travel with you
+ party - a group of characters that travel with you
+ object - inventory item
+ icon - clickable rectangle with some action tied to it
+ dialog - a set of of dialog lines for character. further divided by categories and each entry may have associated
+ condition to be validated
+ global - game-wide storage area. must be preserved when saving/loading
+ phase - current story progress. Incremented by 1 for minor events, by 0x10 for major advancements
+*/
+
+enum Phases {
+ phNewGame = 0
+};
+
+namespace Areas { enum Areas {
+ arMo = 1,
+ arTausCave,
+ arChamaar,
+ arUluru,
+ arKoto,
+ arTamara,
+ arCantura,
+ arShandovra,
+ arNarimsCave,
+ arEmbalmersCave,
+ arWhiteArch,
+ arMoorkusLair
+}; };
+
+#define MKRM(a,l) (((a) << 8) | (l))
+
+enum OBJECT {
+ OBJ_0,
+ OBJ_1,
+ OBJ_2,
+ OBJ_3,
+ OBJ_4,
+ OBJ_PRISME, // 5
+ OBJ_6,
+ OBJ_7,
+ OBJ_OEUF, // 8
+ OBJ_9,
+ OBJ_10,
+ OBJ_CHAMPB, // 11
+ OBJ_CHAMPM, // 12
+ OBJ_COUTEAU, // 13
+ OBJ_NIDV, // 14
+ OBJ_NIDO, // 15
+ OBJ_OR, // 16
+ OBJ_17,
+ OBJ_18,
+ OBJ_SOLEIL, // 19
+ OBJ_CORNE, // 20
+ OBJ_21,
+ OBJ_22,
+ OBJ_23,
+ OBJ_24,
+ OBJ_25,
+ OBJ_26,
+ OBJ_27,
+ OBJ_28,
+ OBJ_29,
+ OBJ_30,
+ OBJ_31,
+ OBJ_32,
+ OBJ_33,
+ OBJ_34,
+ OBJ_35,
+ OBJ_36, // 36 is 1st plaque, 6 total
+ OBJ_37,
+ OBJ_PLAQUE, // 38
+ OBJ_39,
+ OBJ_40,
+ OBJ_41,
+};
+
+namespace Objects { enum Objects {
+ obNone,
+ obWayStone,
+ obShell,
+ obTalisman,
+ obTooth,
+ obPrism, // 5
+ obFlute,
+ obApple,
+ obEgg, // 8
+ obRoot,
+ obUnused10,
+ obShroom, // 11
+ obBadShroom, // 12
+ obKnife, // 13
+ obNest, // 14
+ obFullNest, // 15
+ obGold, // 16
+ obMoonStone,
+ obBag,
+ obSunStone, // 19
+ obHorn, // 20
+ obSword,
+
+ obMaskOfDeath,
+ obMaskOfBonding,
+ obMaskOfBirth,
+
+ obEyeInTheStorm, // 25
+ obSkyHammer,
+ obFireInTheClouds,
+ obWithinAndWithout,
+ obEyeInTheCyclone,
+ obRiverThatWinds,
+
+ obTrumpet, // 31
+ obUnused32,
+ obDrum,
+ obUnused34,
+ obUnused35,
+ obRing,
+
+ obTablet1, // 37 is 1st plaque, 6 total
+ obTablet2,
+ obTablet3, // 39
+ obTablet4,
+ obTablet5,
+ obTablet6
+}; };
+
+enum PERSO {
+ PER_ROI = 0,
+ PER_DINA, // 0x12
+ PER_THOO, // 0x24
+ PER_MONK, // 0x36
+ PER_BOURREAU, // 0x48
+ PER_MESSAGER, // 0x5A
+ PER_MANGO, // 0x6C
+ PER_EVE, // 0x7E
+ PER_AZIA, // 0x90
+ PER_MAMMI, // 0xA2
+ PER_MAMMI_1, // 0xB4
+ PER_MAMMI_2, // 0xC6
+ PER_MAMMI_3, // 0xD8
+ PER_MAMMI_4, // 0xEA
+ PER_MAMMI_5, // 0xFC
+ PER_MAMMI_6, // 0x10E
+ PER_BAMBOO, // 0x120
+ PER_KABUKA, // 0x132
+ PER_GARDES, // 0x144
+ PER_UNKN_156, // 0x156
+ PER_FISHER, // 0x168
+ PER_MORKUS, // 0x17A
+ PER_UNKN_18C, // 0x18C
+ PER_UNKN_19E, // 0x19E
+ PER_UNKN_1B0, // 0x1B0
+ PER_UNKN_1C2, // 0x1C2
+ PER_UNKN_1D4, // 0x1D4
+ PER_UNKN_1E6, // 0x1E6
+ PER_UNKN_1F8, // 0x1F8
+ PER_UNKN_20A, // 0x20A
+ PER_UNKN_21C, // 0x21C
+ PER_UNKN_22E, // 0x22E
+ PER_UNKN_240, // 0x240
+ PER_UNKN_252, // 0x252
+ PER_UNKN_264, // 0x264
+ PER_UNKN_276, // 0x276
+ PER_UNKN_288, // 0x288
+ PER_UNKN_29A, // 0x29A
+ PER_UNKN_2AC, // 0x2AC
+ PER_UNKN_2BE, // 0x2BE
+ PER_UNKN_2D0, // 0x2D0
+ PER_UNKN_2E2, // 0x2E2
+ PER_UNKN_2F4, // 0x2F4
+ PER_UNKN_306, // 0x306
+ PER_UNKN_318, // 0x318
+ PER_UNKN_32A, // 0x32A
+ PER_UNKN_33C, // 0x33C
+ PER_UNKN_34E, // 0x34E
+ PER_UNKN_360, // 0x360
+ PER_UNKN_372, // 0x372
+ PER_UNKN_384, // 0x384
+ PER_UNKN_396, // 0x396
+ PER_UNKN_3A8, // 0x3A8
+ PER_UNKN_3BA, // 0x3BA
+ PER_UNKN_3CC, // 0x3CC
+ PER_UNKN_3DE, // 0x3DE
+ PER_UNKN_3F0, // 0x3F0
+ PER_UNKN_402 // 0x402
+};
+
+namespace PersonId { enum PersonId {
+ pidGregor = 0, // The King
+ pidDina, // Pink dino
+ pidTau, // Late grandpa
+ pidMonk, // Old wizard
+ pidJabber, // Executioner
+ pidEloi, // Evergreen ptero
+ pidMungo, // Dina's husband
+ pidEve, // Blonde girl
+ pidShazia, // Big boobs sis
+ pidLeadersBegin, // 9
+ pidChongOfChamaar = pidLeadersBegin, // Dogface
+ pidKommalaOfKoto, // Clones
+ pidUlanOfUlele, // Shaman
+ pidCabukaOfCantura, // Stone people
+ pidMarindaOfEmbalmers, // Gods
+ pidFuggOfTamara, // Boar-like
+ pidThugg, // Bodyguard
+ pidNarrator, // 16, Old Eloi, also BGM
+ pidNarrim, // Sea snake
+ pidMorkus, // Vicious tyran
+ pidDinosaur, // different species of friendly dino
+ pidEnemy // different species of enemy dino
+}; };
+
+// person in room mask bits
+namespace PersonMask { enum PersonMask {
+ pmGregor = 1,
+ pmDina = 2,
+ pmTau = 4,
+ pmMonk = 8,
+ pmJabber = 0x10,
+ pmEloi = 0x20,
+ pmMungo = 0x40,
+ pmEve = 0x80,
+ pmShazia = 0x100,
+ pmLeader = 0x200, // valley tribe leader
+ pmThugg = 0x400,
+ pmQuest = 0x800, // special quest person
+ pmDino = 0x1000,
+ pmEnemy = 0x2000,
+ pmMorkus = 0x4000
+}; };
+
+namespace PersonFlags { enum PersonFlags {
+ pfType0 = 0,
+ pftTyrann,
+ pfType2,
+ pfType3,
+ pfType4,
+ pfType5,
+ pfType6,
+ pfType7,
+ pfType8,
+ pftMosasaurus,
+ pftTriceraptor,
+ pftVelociraptor,
+ pfType12,
+ pfType13,
+ pfType14,
+ pfType15,
+ pfTypeMask = 0xF,
+ pf10 = 0x10,
+ pf20 = 0x20,
+ pfInParty = 0x40,
+ pf80 = 0x80
+}; };
+
+#pragma pack(push, 1)
+struct perso_t {
+unsigned short roomNum; // room this person currently in
+unsigned short actionId; // TODO: checkme
+unsigned short party; // party bit mask
+unsigned char id; // character
+unsigned char flags; // flags and kind
+unsigned char roomBankIdx;// index in kPersoRoomBankTable for specific room banks
+unsigned char bank; // sprite bank
+unsigned short items; // inventory
+unsigned short powers; // obj of power bitmask
+unsigned char targetLoc; // For party member this is mini sprite index
+unsigned char lastLoc; // For party member this is mini sprite x offset
+unsigned char speed; // num ticks per step
+unsigned char steps; // current ticks
+};
+typedef struct perso_t perso_t;
+
+struct phase_t {
+short id;
+void (EdenGameImpl::*disp)();
+};
+typedef struct phase_t phase_t;
+
+namespace ObjectFlags { enum ObjectFlags {
+ ofFlag1 = 1,
+ ofInHands = 2 // Currently holding this object in hands
+}; };
+
+#define MAX_OBJECTS 42
+struct object_t {
+unsigned char id;
+unsigned char flags;
+int locations; // index in kObjectLocations
+short itemMask;
+short powerMask; // object of power bitmask
+short count;
+};
+typedef struct object_t object_t;
+
+namespace DialogFlags { enum DialogFlags {
+ df20 = 0x20,
+ dfRepeatable = 0x40,
+ dfSpoken = 0x80
+}; };
+
+namespace DialogType { enum DialogType {
+ dtTalk = 0,
+ dtDinoAction,
+ dtDinoItem,
+ dtItem,
+ dtEvent,
+ dtInspect,
+ dtHint
+}; };
+
+struct dial_t {
+char flags; // 0-3 - action index, 4 - highest bit of contidion index, rest is DialogFlags
+char condNumLow; // condition index low bits
+char textCondHiMask; // 0-1 text index hi bits, 2-5 - perso mask num, 6-7 condition index hi bits
+char textNumLow; // text line index low bits
+};
+typedef struct dial_t dial_t;
+
+struct tape_t {
+short textNum;
+perso_t *perso;
+short party;
+short roomNum;
+short bgBankNum;
+dial_t *dialog;
+};
+typedef struct tape_t tape_t;
+
+struct suiveur_t { // Characters on Mirror screen
+char id; // character
+char image; // sprite number
+short sx;
+short sy;
+short ex;
+short ey;
+short bank;
+short ff_C;
+short ff_E;
+};
+typedef struct suiveur_t suiveur_t;
+
+struct icon_t {
+short sx;
+short sy;
+short ex;
+short ey;
+unsigned short cursor_id; // & 0x8000 - inactive/hidden
+unsigned int action_id;
+unsigned int object_id;
+};
+typedef struct icon_t icon_t;
+
+struct goto_t {
+unsigned char areaNum; // target area
+unsigned char curAreaNum; // current area
+unsigned char departVid;
+unsigned char travelTime; // time to skip while in travel
+unsigned char arriveVid;
+};
+typedef struct goto_t goto_t;
+
+namespace RoomFlags { enum RoomFlags {
+ rf01 = 1,
+ rf02 = 2,
+ rf04 = 4,
+ rf08 = 8,
+ rfPanable = 0x10,
+ rfHasCitadel = 0x20,
+ rf40 = 0x40,
+ rf80 = 0x80
+}; };
+
+struct room_t {
+unsigned char ff_0;
+unsigned char exits[4]; //TODO: signed?
+unsigned char flags;
+unsigned short bank;
+unsigned short party;
+unsigned char level; // Citadel level
+unsigned char video;
+unsigned char location;
+unsigned char background; // bg/mirror image number (relative)
+};
+typedef struct room_t room_t;
+
+namespace AreaFlags { enum AreaFlags {
+ afFlag1 = 1,
+ afFlag2 = 2,
+ afFlag4 = 4,
+ afFlag8 = 8,
+ afGaveGold = 0x10,
+ afFlag20 = 0x20,
+
+ HasTriceraptors = 0x100,
+ HasVelociraptors = 0x200,
+ HasTyrann = 0x400,
+
+ TyrannSighted = 0x4000,
+ afFlag8000 = 0x8000
+}; };
+
+namespace AreaType { enum AreaType {
+ atCitadel = 1,
+ atValley = 2,
+ atCave = 3
+}; };
+
+struct area_t {
+unsigned char num;
+unsigned char type;
+unsigned short flags;
+unsigned short firstRoomIndex;
+unsigned char citadelLevel;
+unsigned char salNum;
+room_t *citadelRoom;
+short visitCount;
+};
+typedef struct area_t area_t;
+
+namespace ValleyNews { enum ValleyNews {
+ vnAreaMask = 0xF,
+
+ vnTriceraptorsIn = 0x10,
+ vnVelociraptorsIn = 0x20,
+ vnTyrannIn = 0x30,
+ vnTyrannLost = 0x40,
+ vnCitadelLost = 0x50,
+ vnVelociraptorsLost = 0x60,
+
+ vnFree = 0,
+ vnHidden = 0x80,
+ vnEnd = 0xFF
+}; };
+
+namespace DisplayFlags { enum DisplayFlags {
+ dfFlag1 = 1,
+ dfFlag2 = 2,
+ dfMirror = 4,
+ dfPerson = 8,
+ dfFresques = 0x10,
+ dfPanable = 0x20,
+ dfFlag40 = 0x40,
+ dfFlag80 = 0x80
+}; };
+
+namespace DrawFlags { enum DrawFlags {
+ drDrawInventory = 1,
+ drDrawFlag2 = 2,
+ drDrawTopScreen = 4,
+ drDrawFlag8 = 8,
+ drDrawMenu = 0x10,
+ drDrawFlag20 = 0x20
+}; };
+
+namespace MenuFlags { enum MenuFlags {
+ mfFlag1 = 1,
+ mfFlag2 = 2,
+ mfFlag4 = 4,
+ mfFlag8 = 8,
+ mfFlag10 = 0x10
+}; };
+
+namespace MusicType { enum MusicType { //TODO: same as DialogType?
+ mtDontChange = 0,
+ mtNormal = 1,
+ mt2 = 2,
+ mtEvent = 4,
+ mtFF = 0xFF
+}; };
+
+namespace EventType { enum EventType {
+ etEvent1 = 1,
+ etEvent2 = 2,
+ etEvent3 = 3,
+ etEvent4 = 4,
+ etEvent5 = 5,
+ etEvent6 = 6,
+ etEvent7 = 7,
+ etEvent8 = 8,
+ etEvent9 = 9,
+ etEventB = 11,
+ etEventC = 12,
+ etEventD = 13,
+ etEventE = 14,
+ etEventF = 15,
+ etEvent10 = 16,
+ etEvent12 = 18,
+ etGotoArea = 0x80 // + area id
+}; };
+
+namespace GameFlags { enum GameFlags {
+ gfMummyOpened = 1,
+ gfFlag2 = 2,
+ gfFlag4 = 4,
+ gfFlag8 = 8,
+ gfFlag10 = 0x10,
+ gfFlag20 = 0x20,
+ gfFlag40 = 0x40,
+ gfFlag80 = 0x80,
+ gfFlag100 = 0x100,
+ gfFlag200 = 0x200,
+ gfFlag400 = 0x400,
+ gfPrismAndMonk = 0x800,
+ gfFlag1000 = 0x1000,
+ gfFlag2000 = 0x2000,
+ gfFlag4000 = 0x4000,
+ gfFlag8000 = 0x8000
+}; };
+
+struct global_t {
+unsigned char areaNum;
+unsigned char areaVisitCount;
+unsigned char menuItemIdLo;
+unsigned char menuItemIdHi; //TODO: pad?
+unsigned short randomNumber; //TODO: this is randomized in pc ver and used by some conds. always zero on mac
+unsigned short gameTime;
+unsigned short gameDays;
+unsigned short chrono;
+unsigned short eloiDepartureDay;
+unsigned short roomNum; // current room number
+unsigned short newRoomNum; // target room number selected on world map
+unsigned short phaseNum;
+unsigned short metPersonsMask1;
+unsigned short party;
+unsigned short partyOutside;
+unsigned short metPersonsMask2;
+unsigned short __UNUSED_1C; //TODO: write-only?
+unsigned short phaseActionsCount;
+unsigned short curAreaFlags;
+unsigned short curItemsMask;
+unsigned short curPowersMask;
+unsigned short curPersoItems;
+unsigned short curPersoPowers;
+unsigned short wonItemsMask;
+unsigned short wonPowersMask;
+unsigned short stepsToFindAppleFast;
+unsigned short stepsToFindAppleNormal;
+unsigned short roomPersoItems; //TODO: write-only?
+unsigned short roomPersoPowers; //TODO: write-only?
+unsigned short gameFlags;
+unsigned short curVideoNum;
+unsigned short morkusSpyVideoNum1; //TODO: pad?
+unsigned short morkusSpyVideoNum2; //TODO: pad?
+unsigned short morkusSpyVideoNum3; //TODO: pad?
+unsigned short morkusSpyVideoNum4; //TODO: pad?
+unsigned char newMusicType;
+unsigned char ff_43;
+unsigned char videoSubtitleIndex;
+unsigned char partyInstruments; // &1 - Bell for Monk, &2 - Drum for Thugg
+unsigned char monkGotRing;
+unsigned char chrono_on;
+unsigned char curRoomFlags;
+unsigned char endGameFlag;
+unsigned char last_info;
+unsigned char autoDialog;
+unsigned char worldTyrannSighted;
+unsigned char ff_4D;
+unsigned char ff_4E;
+unsigned char worldGaveGold;
+unsigned char worldHasTriceraptors;
+unsigned char worldHasVelociraptors;
+unsigned char worldHasTyrann;
+unsigned char ff_53;
+unsigned char ff_54;
+unsigned char ff_55; //TODO: pad?
+unsigned char ff_56;
+unsigned char textToken1;
+unsigned char textToken2; //TODO: pad?
+unsigned char eloiHaveNews;
+unsigned char dialogFlags;
+unsigned char curAreaType;
+unsigned char curCitadelLevel;
+unsigned char newLocation;
+unsigned char prevLocation;
+unsigned char curPersoFlags;
+unsigned char ff_60;
+unsigned char eventType;
+unsigned char ff_62; //TODO: pad?
+unsigned char curObjectId;
+unsigned char curObjectFlags;
+unsigned char ff_65; //TODO: pad?
+unsigned char roomPersoType;
+unsigned char roomPersoFlags;
+unsigned char narratorSequence;
+unsigned char ff_69;
+unsigned char ff_6A;
+unsigned char fresqNumber;
+unsigned char ff_6C; //TODO: pad?
+unsigned char ff_6D; //TODO: pad?
+unsigned char labyrinthDirections;
+unsigned char labyrinthRoom;
+void *__UNUSED_70; //TODO: pad?
+dial_t *dialog_ptr;
+tape_t *tape_ptr;
+dial_t *next_dialog_ptr;
+dial_t *narrator_dialog_ptr;
+dial_t *last_dialog_ptr;
+icon_t *nextRoomIcon;
+unsigned char *phraseBufferPtr;
+unsigned char *__UNUSED_90; //TODO: write-only?
+unsigned char *__UNUSED_94; //TODO: write-only?
+room_t *room_ptr;
+area_t *area_ptr;
+area_t *last_area_ptr;
+area_t *cur_area_ptr;
+room_t *cita_area_firstRoom;
+perso_t *perso_ptr;
+perso_t *room_perso;
+unsigned char last_info_idx;
+unsigned char next_info_idx;
+unsigned char *persoSpritePtr;
+unsigned char *persoSpritePtr2;
+unsigned char *curPersoAnimPtr;
+unsigned char *ff_C2; //TODO: image desc arr
+short iconsIndex;
+short curObjectCursor; // TODO: useless?
+short ff_CA;
+short __UNUSED_CC; //TODO: unused/pad
+short perso_img_bank; //TODO: unsigned?
+unsigned short roomImgBank;
+unsigned short persoBackgroundBankIdx;
+unsigned short ff_D4; //TODO: unsigned?
+unsigned short fresqWidth;
+unsigned short fresqImgBank;
+unsigned short ff_DA; //TODO: pad?
+unsigned short ff_DC; //TODO: pad?
+unsigned short room_x_base;
+unsigned short ff_E0; //TODO: pad?
+unsigned short dialogType;
+unsigned short ff_E4; //TODO: pad?
+unsigned short currentMusicNum;
+short textNum;
+unsigned short travelTime;
+unsigned short ff_EC; //TODO: pad?
+unsigned char displayFlags;
+unsigned char oldDisplayFlags;
+unsigned char drawFlags;
+unsigned char ff_F1;
+unsigned char ff_F2;
+unsigned char menuFlags;
+unsigned char ff_F4; //TODO: write-only?
+unsigned char ff_F5;
+unsigned char ff_F6;
+unsigned char ff_F7;
+unsigned char ff_F8; //TODO: pad?
+unsigned char ff_F9; //TODO: pad?
+unsigned char ff_FA; //TODO: pad?
+unsigned char animationFlags;
+unsigned char __UNUSED_FC; //TODO: pad?
+unsigned char giveobj1;
+unsigned char giveobj2;
+unsigned char giveobj3;
+unsigned char ff_100;
+unsigned char roomVidNum;
+unsigned char ff_102;
+unsigned char ff_103;
+unsigned char roomBgBankNum;
+unsigned char valleyVidNum;
+unsigned char updatePaletteFlag;
+unsigned char inventoryScrollPos;
+unsigned char obj_count;
+unsigned char ff_109; //TODO: write-only?
+unsigned char textBankIndex;
+unsigned char pref_language;
+unsigned char pref_10C[2]; //TODO: volume
+unsigned char pref_10E[2]; // -//-
+unsigned char pref_110[2]; // -//-
+unsigned char cita_area_num;
+unsigned char ff_113;
+unsigned char lastSalNum;
+unsigned char save_end;
+short textWidthLimit;
+unsigned char numGiveObjs;
+unsigned char ff_119; // unused
+};
+typedef struct global_t global_t;
+
+struct pakfile_t {
+char name[16];
+long size;
+long offs;
+char flag;
+};
+typedef struct pakfile_t pakfile_t;
+
+struct pak_t {
+unsigned short count;
+pakfile_t files[10];
+};
+typedef struct pak_t pak_t;
+#pragma pack(pop)
+
+struct cita_t {
+short ff_0;
+short ff_2[8 * 2];
+};
+typedef struct cita_t cita_t;
+
+/////////////// vars
+
+suiveur_t suiveurs_list[] = {
+// char, X, sx, sy, ex, ey,bank,
+ { PersonId::pidGregor, 5, 211, 9, 320, 176, 228, 0, 0 },
+ { PersonId::pidEloi, 4, 162, 47, 223, 176, 228, 112, 78 },
+ { PersonId::pidDina, 3, 55, 0, 172, 176, 228, 90, 16 },
+ { PersonId::pidChongOfChamaar, 4, 0, 5, 114, 176, 229, 0, 16 },
+ { PersonId::pidKommalaOfKoto, 3, 0, 15, 102, 176, 229, 0, 16 },
+ { PersonId::pidUlanOfUlele, 1, 0, 0, 129, 176, 230, 0, 16 },
+ { PersonId::pidCabukaOfCantura, 2, 0, 0, 142, 176, 230, 0, 16 },
+ { PersonId::pidFuggOfTamara, 0, 0, 17, 102, 176, 230, 0, 16 },
+ { PersonId::pidJabber, 2, 0, 6, 134, 176, 228, 0, 16 },
+ { PersonId::pidShazia, 1, 90, 17, 170, 176, 228, 50, 22 },
+ { PersonId::pidThugg, 0, 489, 8, 640, 176, 228, 160, 24 },
+ { PersonId::pidMungo, 5, 361, 0, 517, 176, 229, 0, 16 },
+ { PersonId::pidMonk, 0, 419, 22, 569, 176, 229, 100, 30 },
+ { PersonId::pidEve, 1, 300, 28, 428, 176, 229, 0, 38 },
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+};
+
+
+/*
+ Labyrinth of Mo
+
+ | | | | | | | |
+
+*/
+
+enum {
+ LAB_N = 1,
+ LAB_E,
+ LAB_S,
+ LAB_W
+};
+
+#define LAB(toCrypt, toThrone) \
+ (((LAB_##toCrypt) << 4) | (LAB_##toThrone))
+
+unsigned char kLabyrinthPath[] = {
+// each nibble tells wich direction to choose to exit the labyrinth
+0x11, 0x11, 0x11, 0x22, 0x33, 0x55, 0x25, 0x44, 0x25, 0x11, 0x11, 0x11,
+0x11, 0x35, 0x55, 0x45, 0x45, 0x44, 0x44, 0x34, 0x44, 0x34, 0x32, 0x52,
+0x33, 0x23, 0x24, 0x44, 0x24, 0x22, 0x54, 0x22, 0x54, 0x54, 0x44, 0x22,
+0x22, 0x42, 0x45, 0x22, 0x42, 0x45, 0x35, 0x11, 0x44, 0x34, 0x52, 0x11,
+0x44, 0x32, 0x55, 0x11, 0x11, 0x33, 0x11, 0x11, 0x53, 0x11, 0x11, 0x53,
+0x54, 0x24, 0x11, 0x22, 0x25, 0x33, 0x53, 0x54, 0x23, 0x44
+};
+
+#undef LAB
+
+char kDinoSpeedForCitaLevel[16] = { 1, 2, 3, 4, 4, 5, 6, 7, 8, 9 };
+
+char kTabletView[] = { //TODO: make as struct?
+ // opposite tablet id, video id
+ Objects::obUnused10, 83,
+ Objects::obUnused10, 84,
+ Objects::obTablet4, 85,
+ Objects::obTablet3, 86,
+ Objects::obTablet6, 87,
+ Objects::obTablet5, 85
+};
+
+// special character backgrounds for specific rooms
+char kPersoRoomBankTable[] = {
+ // first entry is default bank, then pairs of [roomNum, bankNum], terminated by -1
+ 0, 3, 33, -1,
+ 21, 17, 35, -1,
+ 0, 2, 36, -1,
+ 22, 9, 38, 3, 39, -1,
+ 23, 8, 40, -1,
+ 0, 3, 41, 7, 42, -1,
+ 25, -1,
+ 27, 17, 45, -1,
+ 28, 26, 46, -1,
+ 29, 51, 48, -1,
+ 30, 53, 49, -1,
+ 0, 27, 50, -1,
+ 32, 17, 51, -1,
+ 52, 2, 52, -1,
+ -3, 3, -3, -1,
+ 31, -1,
+ 24, 6, 43, -1,
+ 47, -1,
+ 0, 2, 64, -1,
+ 54, 3, 54, -1,
+ 27, -1,
+ 26, 17, 45, -1
+};
+
+// area transition descriptors
+goto_t gotos[] = {
+// area, oldarea, vid, time, valleyVid
+ { 0, 1, 0, 2, 20 },
+ { 0, 1, 162, 3, 168 },
+ { 0, 2, 0, 2, 21 },
+ { 0, 6, 0, 3, 108 },
+ { 0, 9, 151, 3, 0 },
+ { 0, 7, 106, 2, 101 },
+ { 0, 10, 79, 3, 102 },
+ { 0, 12, 0, 3, 0 },
+ { -1, -1, -1, -1, -1 },
+ { 1, 3, 58, 2, 104 },
+ { 1, 4, 100, 4, 104 },
+ { 1, 5, 107, 6, 104 },
+ { 1, 6, 155, 8, 104 },
+ { 1, 7, 165, 6, 104 },
+ { 1, 8, 169, 6, 104 },
+ { 1, 10, 111, 2, 104 },
+ { 1, 11, 164, 4, 104 },
+ { -1, -1, -1, -1, -1 },
+ { 1, 3, 161, 3, 102 },
+ { 1, 4, 163, 6, 102 },
+ { 1, 5, 157, 9, 102 },
+ { 1, 9, 160, 9, 102 },
+ { 1, 10, 79, 3, 102 },
+ { -1, -1, -1, -1, -1 },
+ { 1, 3, 0, 3, 153 },
+ { -1, -1, -1, -1, -1 },
+ { 3, 1, 154, 2, 103 },
+ { 3, 4, 100, 2, 103 },
+ { 3, 5, 107, 4, 103 },
+ { 3, 6, 155, 6, 103 },
+ { 3, 7, 165, 8, 103 },
+ { 3, 8, 169, 6, 103 },
+ { 3, 10, 111, 4, 103 },
+ { 3, 11, 164, 6, 103 },
+ { -1, -1, -1, -1, -1 },
+ { 3, 1, 162, 3, 22 },
+ { 3, 4, 163, 6, 22 },
+ { 3, 5, 157, 9, 22 },
+ { 3, 9, 160, 9, 22 },
+ { -1, -1, -1, -1, -1 },
+ { 3, 1, 0, 3, 166 },
+ { -1, -1, -1, -1, -1 },
+ { 4, 1, 154, 4, 51 },
+ { 4, 3, 58, 2, 51 },
+ { 4, 5, 107, 2, 51 },
+ { 4, 6, 155, 4, 51 },
+ { 4, 7, 165, 6, 51 },
+ { 4, 8, 169, 8, 51 },
+ { 4, 10, 111, 6, 51 },
+ { 4, 11, 164, 8, 51 },
+ { -1, -1, -1, -1, -1 },
+ { 4, 1, 162, 3, 109 },
+ { 4, 3, 161, 6, 109 },
+ { 4, 5, 157, 9, 109 },
+ { 4, 9, 160, 9, 109 },
+ { -1, -1, -1, -1, -1 },
+ { 5, 1, 154, 6, 33 },
+ { 5, 3, 58, 4, 33 },
+ { 5, 4, 100, 2, 33 },
+ { 5, 6, 155, 2, 33 },
+ { 5, 7, 165, 4, 33 },
+ { 5, 8, 169, 8, 33 },
+ { 5, 10, 111, 8, 33 },
+ { 5, 11, 164, 8, 33 },
+ { -1, -1, -1, -1, -1 },
+ { 5, 1, 162, 3, 99 },
+ { 5, 3, 161, 6, 99 },
+ { 5, 4, 163, 9, 99 },
+ { 5, 9, 160, 9, 99 },
+ { -1, -1, -1, -1, -1 },
+ { 9, 1, 162, 3, 167 },
+ { 9, 3, 161, 6, 167 },
+ { 9, 4, 163, 9, 167 },
+ { 9, 5, 157, 9, 167 },
+ { -1, -1, -1, -1, -1 },
+ { 6, 1, 154, 8, 105 },
+ { 6, 3, 58, 6, 105 },
+ { 6, 4, 100, 4, 105 },
+ { 6, 5, 107, 2, 105 },
+ { 6, 7, 165, 2, 105 },
+ { 6, 8, 169, 10, 105 },
+ { 6, 10, 111, 6, 105 },
+ { 6, 11, 164, 8, 105 },
+ { -1, -1, -1, -1, -1 },
+ { 7, 1, 154, 4, 158 },
+ { 7, 3, 58, 6, 158 },
+ { 7, 4, 100, 6, 158 },
+ { 7, 5, 107, 4, 158 },
+ { 7, 6, 155, 2, 158 },
+ { 7, 8, 169, 8, 158 },
+ { 7, 10, 111, 4, 158 },
+ { 7, 11, 164, 6, 158 },
+ { -1, -1, -1, -1, -1 },
+ { 8, 1, 154, 2, 159 },
+ { 8, 3, 58, 4, 159 },
+ { 8, 4, 100, 6, 159 },
+ { 8, 5, 107, 8, 159 },
+ { 8, 6, 155, 10, 159 },
+ { 8, 7, 165, 8, 159 },
+ { 8, 10, 111, 6, 159 },
+ { 8, 11, 164, 4, 159 },
+ { -1, -1, -1, -1, -1 },
+ { 10, 1, 154, 2, 77 },
+ { 10, 3, 58, 4, 77 },
+ { 10, 4, 100, 6, 77 },
+ { 10, 5, 107, 8, 77 },
+ { 10, 6, 155, 6, 77 },
+ { 10, 7, 165, 4, 77 },
+ { 10, 8, 169, 6, 77 },
+ { 10, 11, 164, 4, 77 },
+ { -1, -1, -1, -1, -1 },
+ { 11, 1, 154, 2, 80 },
+ { 11, 3, 58, 4, 80 },
+ { 11, 4, 100, 6, 80 },
+ { 11, 5, 107, 8, 80 },
+ { 11, 6, 155, 8, 80 },
+ { 11, 7, 165, 6, 80 },
+ { 11, 8, 169, 2, 80 },
+ { 11, 10, 111, 4, 80 },
+ { -1, -1, -1, -1, -1 },
+ { 12, 1, 154, 8, 56 },
+ { 12, 3, 58, 4, 56 },
+ { 12, 4, 100, 4, 56 },
+ { 12, 5, 107, 6, 56 },
+ { 12, 6, 155, 8, 56 },
+ { 12, 7, 165, 10, 56 },
+ { 12, 8, 169, 4, 56 },
+ { 12, 10, 111, 10, 56 },
+ { 12, 11, 164, 6, 56 },
+ { -1, -1, -1, -1, -1 }
+};
+
+#define SUB_LINE(start, end) \
+ (start), (end) | 0x8000
+
+short tab_2D24C[] = {
+ SUB_LINE( 68, 120 ),
+ 123, 32964,
+ 199, 33042,
+ 276, 33138,
+ 799, 33653,
+ 888, 33708,
+ 947, 33768,
+ 1319, 34146,
+ 1380, 34208,
+ 1854, 34666,
+ 1900, 34728,
+ 2116, 34952,
+ 2186, 35020,
+ 2254, 35088,
+ 3038, 35862,
+ 3096, 35928,
+ -1
+};
+
+short tab_2D28E[] = {
+ 99, 32923,
+ 157, 33024,
+ -1
+};
+
+short tab_2D298[] = {
+ 106, 32941,
+ 175, 33012,
+ 246, 33118,
+ 352, 33235,
+ -1
+};
+
+short tab_2D2AA[] = {
+ 126, 32944,
+ 178, 33035,
+ 269, 33110,
+ 344, 33166,
+ 400, 33226,
+ 460, 33326,
+ -1
+};
+
+short tab_2D2C4[] = {
+ 101, 32981,
+ 215, 33121,
+ 355, 33223,
+ 457, 33286,
+ 520, 33428,
+ 662, 33536,
+ -1
+};
+#undef SUB_LINE
+
+object_t objects[] = {
+ //id,fl,loc,masklow,maskhi,ct
+ { 1, 0, 3, 1, 0, 0}, // Eve's Way Stone
+ { 2, 0, 3, 2, 0, 0}, // Thau's Seashell
+ { 3, 0, 3, 4, 0, 0}, // Talisman of bravery
+ { 4, 0, 3, 8, 0, 0}, // An old tooth. Very old! Whoever lost it most certainly has no further use for it!
+ { 5, 0, 0, 0x10, 0, 0}, // Prism
+ { 6, 0, 3, 0, 0, 0}, // Flute
+ { 7, 0, 3, 0x4000, 0, 0}, // Apple
+ { 8, 0, 4, 0x1000, 0, 0}, // Egg of Destiny
+ { 9, 0, 3, 0x800, 0, 0}, // Root
+ { 10, 0, 3, 0, 0, 0}, // ???
+ { 11, 0, 6, 0, 0, 0}, // Mushroom
+ { 12, 0, 13, 0, 0, 0}, // Poisonous Mushroom
+ { 13, 0, 2, 0x400, 0, 0}, // Graa's Knife
+ { 14, 0, 22, 0, 0, 0}, // Empty Nest
+ { 15, 0, 26, 0, 0, 0}, // Full Nest
+ { 16, 0, 33, 0x20, 0, 0}, // Gold
+ { 17, 0, 3, 0, 0, 0}, // Sign of Shadow Mistress (moon stone)
+ { 18, 0, 3, 0, 0, 0}, // Sign of Mother of all (bag of soil)
+ { 19, 0, 40, 0, 0, 0}, // Sign of the life-giving (sun star)
+ { 20, 0, 20, 0x200, 0, 0}, // King's Horn
+ { 21, 0, 3, 0, 0, 0}, // Golden Sword of Mashaar
+ // Masks
+ { 22, 0, 3, 0x40, 0, 0}, // Mask of Death
+ { 23, 0, 3, 0x80, 0, 0}, // Mask of Bonding
+ { 24, 0, 3, 0x100, 0, 0}, // Mask of Birth
+ // Objects of power
+ { 25, 0, 3, 0, 1, 0}, // Eye in the Storm
+ { 26, 0, 3, 0, 2, 0}, // Sky Hammer
+ { 27, 0, 3, 0, 4, 0}, // Fire in the Clouds
+ { 28, 0, 3, 0, 8, 0}, // Within and Without
+ { 29, 0, 3, 0, 0x10, 0}, // Eye in the Cyclone
+ { 30, 0, 3, 0, 0x20, 0}, // River that Winds
+ // Musical instruments
+ { 31, 0, 3, 0, 0x40, 0}, // Trumpet
+ { 32, 0, 3, 0, 0x80, 0}, // -- unused (but still has a dialog line)
+ { 33, 0, 3, 0, 0x100, 0}, // Drum
+ { 34, 0, 3, 0, 0x200, 0}, // -- unused (but still has a dialog line)
+ { 35, 0, 3, 0, 0x400, 0}, // -- unused (but still has a dialog line)
+ { 36, 0, 3, 0, 0x800, 0}, // Ring
+ // Tablets
+ { 37, 0, 3, 0, 0, 0}, // Tablet #1 (Mo)
+ { 38, 0, 42, 0x2000, 0, 0}, // Tablet #2 (Morkus' Lair)
+ { 39, 0, 3, 0, 0, 0}, // Tablet #3 (White Arch?)
+ { 40, 0, 3, 0, 0, 0}, // Tablet #4
+ { 41, 0, 3, 0, 0, 0}, // Tablet #5
+ { 42, 0, 3, 0x8000, 0, 0} // Tablet #6 (Castra)
+};
+
+short kObjectLocations[100] = {
+ 0x112, -1,
+ 0x202, -1,
+ 0x120, -1,
+ 0x340, 0x44B, 0x548, 0x640, 0x717, 0x830, -1,
+ 0x340, 0x44B, 0x548, 0x640, 0x717, 0x830, -1,
+ 0, -1,
+ 0x344, 0x53A, 0x831, -1,
+ 0x331, 0x420, 0x54B, 0x637, 0x716, 0x840, -1,
+ 0x834A, 0x8430, 0x8531, 0x644, 0x745, 0x838, -1,
+ 0x510, -1,
+ 0xC04, -1,
+ -1
+};
+
+perso_t kPersons[] = {
+ // room, aid, party mask, id, flags, X,bank,X, X,sprId,sprX,speed, X
+ { 0x103, 230, PersonMask::pmGregor, PersonId::pidGregor , 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+ { 0x116, 231, PersonMask::pmDina , PersonId::pidDina , 0, 4, 2, 0, 0, 3, 9, 0, 0 },
+ { 0x202, 232, PersonMask::pmTau , PersonId::pidTau , 0, 8, 3, 0, 0, 0, 0, 0, 0 },
+ { 0x109, 233, PersonMask::pmMonk , PersonId::pidMonk , 0, 12, 4, 0, 0, 6, 52, 0, 0 },
+ { 0x108, 234, PersonMask::pmJabber, PersonId::pidJabber , 0, 18, 5, 0, 0, 2, 0, 0, 0 },
+ { 0x103, 235, PersonMask::pmEloi , PersonId::pidEloi , 0, 22, 6, 0, 0, 4, 20, 0, 0 },
+ { 0x301, 236, PersonMask::pmMungo , PersonId::pidMungo , 0, 28, 8, 0, 0, 11, 45, 0, 0 },
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 30, 10, 0, 0, 7, 35, 0, 0 },
+ { 0x81A, 238, PersonMask::pmShazia, PersonId::pidShazia , 0, 34, 11, 0, 0, 1, 11, 0, 0 },
+ { 0x330, 239, PersonMask::pmLeader, PersonId::pidChongOfChamaar , 0, 38, 13, 0, 0, 10, 0, 0, 0 },
+ { 0x41B, 239, PersonMask::pmLeader, PersonId::pidUlanOfUlele , 0, 46, 15, 0, 0, 13, 0, 0, 0 },
+ { 0x53B, 239, PersonMask::pmLeader, PersonId::pidKommalaOfKoto , 0, 42, 14, 0, 0, 9, 0, 0, 0 },
+ { 0x711, 239, PersonMask::pmLeader, PersonId::pidCabukaOfCantura , 0, 50, 16, 0, 0, 14, 0, 0, 0 },
+ { 0xA02, 239, PersonMask::pmLeader, PersonId::pidMarindaOfEmbalmers, 0, 54, 17, 0, 0, 0, 0, 0, 0 },
+ { 0x628, 239, PersonMask::pmLeader, PersonId::pidFuggOfTamara , 0, 62, 18, 0, 0, 12, 0, 0, 0 },
+ { 0x801, 239, PersonMask::pmLeader, PersonId::pidChongOfChamaar , 0, 38, 13, 0, 0, 10, 0, 0, 0 },
+ { 0x41B, 10, PersonMask::pmQuest , PersonId::pidUlanOfUlele , PersonFlags::pfType2 , 46, 15, 0, 0, 13, 0, 0, 0 },
+ { 0x711, 11, PersonMask::pmQuest , PersonId::pidCabukaOfCantura , PersonFlags::pfType2 , 50, 16, 0, 0, 14, 0, 0, 0 },
+ { 0x106, 240, PersonMask::pmThugg , PersonId::pidThugg , 0, 64, 7, 0, 0, 0, 61, 0, 0 },
+ { 0, 13, 0, PersonId::pidNarrator , 0, 68, 12, 0, 0, 0, 0, 0, 0 },
+ { 0x902, 241, PersonMask::pmQuest , PersonId::pidNarrim , 0, 70, 19, 0, 0, 0, 0, 0, 0 },
+ { 0xC03, 244, PersonMask::pmMorkus, PersonId::pidMorkus , 0, 74, 20, 0, 0, 0, 0, 0, 0 },
+ // dinos in each valley
+ { 0x332, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x329, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x33B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x317, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x320, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType12 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x349, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x429, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x43B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x422, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x432, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x522, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x534, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x515, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pftVelociraptor , 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x533, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x622, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x630, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x643, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x63A, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x737, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x739, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x74A, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x726, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x842, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x822, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x828, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pftVelociraptor , 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x84B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0xB03, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 58,252, 0, 0, 0, 0, 0, 0 },
+ // enemy dinos
+ { 0x311, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x410, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x51B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x618, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x71B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x81B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { -1, -1, -1, -1, -1, -1, -1,-1,-1, -1, -1,-1,-1 },
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 80, 9, 0, 0, 8, 35, 0, 0 },
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 78, 10, 0, 0, 7, 35, 0, 0 }
+};
+
+cita_t cita_list[] = {
+ {1,
+ {163, 182, 0, 0,
+ 124, 147, 193, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0}},
+ {48,
+ {285, 286, 0, 0,
+ 287, 288, 284, 0,
+ 114, 115, 0, 0,
+ 116, 117, 113, 0}},
+ {63,
+ {290, 291, 0, 0,
+ 292, 293, 289, 0,
+ 119, 120, 0, 0,
+ 121, 122, 118, 0}},
+ {95,
+ {295, 296, 0, 0,
+ 297, 298, 294, 0,
+ 124, 125, 0, 0,
+ 126, 127, 123, 0}},
+ {127,
+ {300, 301, 0, 0,
+ 302, 303, 299, 0,
+ 129, 130, 0, 0,
+ 131, 132, 128, 0}},
+ {159,
+ {305, 306, 0, 0,
+ 307, 308, 304, 0,
+ 134, 135, 0, 0,
+ 136, 137, 133, 0}},
+ {255,
+ {310, 311, 0, 0,
+ 312, 313, 309, 0,
+ 139, 140, 0, 0,
+ 141, 142, 138, 0}}
+};
+
+
+short tab_2CB16[] = { 2075, 2080, 2119, -1};
+
+char tab_2CB1E[8][4] = {
+ { 0x10, 0x81, 1, 0x90},
+ { 0x90, 1, 0x81, 0x10},
+ { 1, 0x90, 0x10, 0x81},
+ { 1, 0x10, 0x90, 0x81},
+ { 1, 0x90, 0x10, 0x81},
+ { 0x81, 0x10, 0x90, 1},
+ { 0x81, 0x10, 0x90, 1},
+ { 0x81, 0x90, 1, 0x10}
+};
+
+struct prect_t {
+short sx, sy, ex, ey;
+};
+typedef struct prect_t prect_t;
+
+prect_t perso_rects[] = { //TODO: just an array of shorts?
+ { 93, 69, 223, 176},
+ { 102, 86, 162, 126},
+ { 88, 103, 168, 163},
+ { 116, 66, 192, 176},
+ { 129, 92, 202, 153},
+ { 60, 95, 160, 176},
+ { 155, 97, 230, 145},
+ { 100, 77, 156, 145},
+ { 110, 78, 170, 156},
+ { 84, 76, 166, 162},
+ { 57, 77, 125, 114},
+ { 93, 69, 223, 175},
+ { 93, 69, 223, 176},
+ { 93, 69, 223, 176},
+ { 154, 54, 245, 138},
+ { 200, 50, 261, 116},
+ { 70, 84, 162, 176},
+ { 125, 101, 222, 172},
+ { 188, 83, 251, 158}
+};
+
+unsigned char tab_persxx[][5] = { //TODO: struc?
+ { 8, 15, 23, 25, -1},
+ { 0, 9, -1 },
+ { 0, 9, -1 },
+ { 0, 9, -1 },
+ { 0, 13, -1 },
+ { 16, 21, -1 },
+ { 11, 20, -1 },
+ { 0, 12, -1 },
+ { 0, 9, -1 },
+ { 0, 9, -1 },
+ { 5, 13, -1 },
+ { -1 },
+ { 0, 8, -1 },
+ { -1 },
+ { 0, 7, -1 },
+ { 0, 8, -1 },
+ { 8, 12, -1 },
+ { 0, 5, -1 },
+ { 0, 4, -1 },
+ { -1 }
+};
+
+area_t kAreasTable[] = {
+ { Areas::arMo , AreaType::atCitadel, 0, 0, 0, 1},
+ { Areas::arTausCave , AreaType::atCave , 0, 112, 0, 2},
+ { Areas::arChamaar , AreaType::atValley , 0, 133, 0, 3},
+ { Areas::arUluru , AreaType::atValley , 0, 187, 0, 4},
+ { Areas::arKoto , AreaType::atValley , AreaFlags::HasVelociraptors, 236, 0, 5},
+ { Areas::arTamara , AreaType::atValley , 0, 288, 0, 6},
+ { Areas::arCantura , AreaType::atValley , 0, 334, 0, 7},
+ { Areas::arShandovra , AreaType::atValley , 0, 371, 0, 8},
+ { Areas::arNarimsCave , AreaType::atCave , 0, 115, 0, 9},
+ { Areas::arEmbalmersCave, AreaType::atCave , 0, 118, 0, 10},
+ { Areas::arWhiteArch , AreaType::atCave , 0, 122, 0, 11},
+ { Areas::arMoorkusLair , AreaType::atCave , 0, 127, 0, 12}
+};
+
+short tab_2CEF0[64] = {
+ 25, 257, 0, 0, 37, 258, 38, 259, 0, 0, 24, 260, 0, 0, 0, 0,
+ 0, 0, 53, 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 39, 261, 0, 0, 40, 262, 62, 263, 0, 0, 63, 264, 0, 0, 0, 0,
+ 18, 275, 0, 0, 35, 254, 36, 255, 19, 318, 23, 256, 0, 0, 0, 0
+};
+
+short tab_2CF70[64] = {
+ 65, 266, 0, 0, 66, 267, 67, 268, 0, 0, 68, 269, 0, 0, 0, 0,
+ 0, 0, 73, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 69, 270, 0, 0, 70, 271, 71, 272, 0, 0, 72, 273, 0, 0, 0, 0,
+ 18, 275, 0, 0, 35, 254, 36, 255, 19, 318, 23, 256, 0, 0, 0, 0,
+};
+
+short kActionCursors[299] = {
+ 3, 1, 2, 4, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 3, 2, 5, 5, 5, 3, 2,
+ 4, 5, 7, 7, 4, 5, 5, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 0, 5, 6,
+ 6, 1, 6, 6, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 0, 0, 6, 6,
+ 53, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+struct cubeface_t {
+int tri;
+char ff_4;
+char ff_5;
+
+unsigned char *texptr;
+unsigned short *indices;
+short *uv;
+};
+typedef struct cubeface_t cubeface_t;
+
+struct cube_t {
+int num;
+cubeface_t **faces;
+short *projection; // projected XYZ coords
+short *vertices;
+};
+typedef struct cube_t cube_t;
+
+float flt_2DF7C = -3400;
+float flt_2DF80 = -3400;
+float flt_2DF84 = 200;
+
+// Cube faces to texture coords mapping
+// each entry is num_polys(6) * num_faces_per_poly(2) * vertex_per_face(3) * uv(2)
+
+short cube_texcoords[3][6 * 2 * 3 * 2] = {
+ {
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32,
+
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 0, 0, 32, 0, 32, 32,
+ 0, 0, 32, 32, 0, 32,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32
+ }, {
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0
+ }, {
+ 30, 30, 2, 30, 2, 2,
+ 30, 30, 2, 2, 30, 2,
+
+ 2, 30, 2, 2, 30, 2,
+ 2, 30, 30, 2, 30, 30,
+
+ 30, 30, 2, 30, 2, 2,
+ 30, 30, 2, 2, 30, 2,
+
+ 30, 2, 30, 30, 2, 30,
+ 30, 2, 2, 30, 2, 2,
+
+ 2, 2, 30, 2, 30, 30,
+ 2, 2, 30, 30, 2, 30,
+
+ 2, 30, 2, 2, 30, 2,
+ 2, 30, 30, 2, 30, 30
+ }
+};
+
+char tab_2E138[4 * 3] = {
+ 0, 0, 1, 1,
+ 0, 0, 0, 1,
+ 0, 0, 2, 0
+};
diff --git a/engines/cryo/detection.cpp b/engines/cryo/detection.cpp
new file mode 100644
index 0000000000..1d6f145c78
--- /dev/null
+++ b/engines/cryo/detection.cpp
@@ -0,0 +1,131 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+#include "common/file.h"
+
+#include "cryo/cryo.h"
+
+
+namespace Cryo {
+
+const char *CryoEngine::getGameId() const {
+ return _gameDescription->gameId;
+}
+
+}
+
+static const PlainGameDescriptor cryoGames[] = {
+ {"losteden", "Lost Eden"},
+ {0, 0}
+};
+
+namespace Cryo {
+
+static const ADGameDescription gameDescriptions[] = {
+
+ // Lost Eden PC non-interactive demo version
+ // Probably not worth it
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN6.HSQ", nullptr, 17093),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden PC interactive demo version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", nullptr, 205473728),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden PC version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", nullptr, 449853776),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden Mac version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", nullptr, 489739536),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Cryo
+
+class CryoMetaEngine : public AdvancedMetaEngine {
+public:
+ CryoMetaEngine() : AdvancedMetaEngine(Cryo::gameDescriptions, sizeof(ADGameDescription), cryoGames) {
+ _singleId = "losteden";
+ }
+
+ virtual const char *getName() const {
+ return "Cryo Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Cryo Engine (C) Cryo Interactive";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+};
+
+bool CryoMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return false;
+}
+
+bool CryoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Cryo::CryoEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(CRYO)
+ REGISTER_PLUGIN_DYNAMIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
+#endif
diff --git a/engines/cryo/eden.cpp b/engines/cryo/eden.cpp
new file mode 100644
index 0000000000..02fc66bf52
--- /dev/null
+++ b/engines/cryo/eden.cpp
@@ -0,0 +1,9457 @@
+//#include <stdint.h>
+
+#include "common/scummsys.h"
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "gui/EventRecorder.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/fs.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+#include "common/timer.h"
+
+//#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "cryo/cryo.h"
+#include "cryo/eden.h"
+
+namespace Cryo {
+
+#include "cryo/platdefs.h"
+#include "cryo/defs.h"
+#include "cryo/CryoLib.h"
+#include "cryo/CryoLibStub.c"
+
+short word_2C300 = 0;
+short word_2C302 = 0;
+short word_2C304 = 0;
+
+unsigned char allow_doubled = 1;
+int curs_center = 11;
+
+struct {
+ short x, y;
+} saved_repadam = { -1, -1 };
+
+class EdenGameImpl : EdenGame {
+private:
+
+short old_scroll_pos, scroll_pos;
+short word_2F514;
+unsigned char fresqTalk;
+unsigned char keep01, keep02, keep10, keep11, keep12, keep13, keep21, keep22;
+unsigned char curs_keepbuf[2500];
+short curs_keepy, curs_keepx;
+short torchCursor;
+short cur_bank_num;
+short glow_h;
+short glow_w;
+short glow_y;
+short glow_x;
+unsigned char needPaletteUpdate;
+unsigned char curs_saved;
+unsigned char showBlackBars;
+unsigned char fond_saved;
+unsigned char *bank_data_ptr;
+color3_t pal_entry;
+color_t global_palette[256]; //TODO palette_t
+perso_t *tyranPtr;
+int last_anim_frame_num;
+int cur_anim_frame_num;
+int last_anim_ticks;
+prect_t *cur_perso_rect;
+short num_anim_frames;
+short max_perso_desc;
+short num_img_desc;
+unsigned char restartAnimation;
+unsigned char animationActive;
+unsigned char animationDelay;
+unsigned char animationIndex;
+unsigned char lastAnimationIndex;
+
+unsigned char *dword_30724;
+unsigned char *dword_30728; //TODO: rename - something amim-related
+unsigned char *dword_3072C; //TODO ditto
+unsigned char *animationTable;
+unsigned char imagedesc[512];
+unsigned char *perso_img_bank_data_ptr;
+unsigned char savedUnderSubtitles;
+short num_text_lines;
+unsigned char phraseBuffer[400];
+unsigned char *text_ptr;
+unsigned char phraseIconsBuffer[10];
+unsigned char phraseCoordsBuffer[22];
+unsigned char *textoutptr;
+unsigned char *textout;
+object_t *currentSpecialObject;
+short word_30AFC;
+unsigned char byte_30AFE;
+
+unsigned char byte_30B00;
+int dword_30B04;
+
+char lastPhrasesFile;
+char dialogSkipFlags;
+
+color3_t newColor;
+color_t oldPalette[256]; // TODO palette_t ?
+color_t newPalette[256];
+rect_t rect_dst, rect_src;
+void *voiceSamplesBuffer; //TODO: sound sample buffer
+file_t h_bigfile;
+unsigned char info_list[16];
+unsigned char needToFade;
+unsigned char lastMusicNum;
+unsigned char *main_bank_buf;
+unsigned char *music_buf;
+unsigned char *gameLipsync;
+unsigned char *gamePhrases;
+unsigned char *gameDialogs; //TODO: rename to dialogs?
+unsigned char *gameConditions;
+void *sal_buf; //TODO: fixme
+unsigned char *bank_data_buf;
+icon_t *gameIcons;
+room_t *gameRooms;
+pak_t *bigfile_header;
+unsigned char *glow_buffer;
+unsigned char *p_mainview_buf;
+unsigned char *p_view2_buf;
+unsigned char *gameFont; //TODO: rename to font?
+unsigned char *p_subtitlesview_buf;
+unsigned char *p_underSubtitlesView_buf;
+global_t *p_global;
+unsigned short mouse_y_center, mouse_x_center;
+int quit_flag3; //TODO: some obsolete error flag?
+unsigned short machine_speed;
+unsigned char quit_flag;
+
+unsigned char gameStarted;
+
+unsigned char quit_flag2;
+unsigned char soundAllocated;
+soundchannel_t *music_channel;
+soundchannel_t *hnmsound_ch;
+sound_t *voiceSound;
+
+view_t *p_view2;
+view_t *p_underSubtitlesView;
+view_t *p_subtitlesview;
+view_t *p_underBarsView;
+view_t *p_mainview;
+view_t *p_hnmview;
+hnm_t *p_hnmcontext;
+filespec_t bigfilespec;
+rect_t underSubtitlesBackupRect, underSubtitlesScreenRect, underBottomBarBackupRect, underBottomBarScreenRect,
+ underTopBarBackupRect, underTopBarScreenRect, rect_31C7A;
+int demoCurrentTicks;
+int demoStartTicks;
+int currentTime;
+short mouse_y;
+short mouse_x;
+short doubled;
+short curs_x_pan;
+short inventoryScrollDelay;
+short curs_y, curs_x;
+short current_cursor;
+icon_t *current_spot;
+icon_t *current_spot2;
+unsigned char pomme_q;
+unsigned char keybd_held;
+unsigned char mouse_held;
+unsigned char normalCursor;
+unsigned char *p_hnmview_buf;
+unsigned char showVideoSubtitle;
+unsigned char videoCanceled; //TODO: hnm_canceled
+unsigned char specialTextMode;
+int hnm_position;
+int voiceSamplesSize; //TODO: perso vox sample data len
+short mus_vol_right;
+short mus_vol_left;
+
+
+unsigned char animateTalking;
+unsigned char personTalking;
+unsigned char mus_fade_flags;
+
+char musicSequencePos;
+unsigned char musicPlaying;
+
+unsigned char *mus_samples_ptr;
+unsigned char *mus_patterns_ptr; //TODO: sndblock_t ?
+unsigned char *mus_sequence_ptr;
+soundgroup_t *mus_queue_grp;
+short *pCurrentObjectLocation;
+unsigned char own_objects[128];
+unsigned char byte_31D64;
+
+unsigned char no_palette;
+unsigned char gameLoaded;
+#define MAX_TAPES 16
+tape_t tapes[MAX_TAPES];
+unsigned char confirmMode;
+unsigned char *cur_slider_value_ptr;
+unsigned char lastMenuItemIdLo;
+short lastTapeRoomNum;
+short cur_slider_x;
+short cur_slider_y;
+short destinationRoom;
+short word_31E7A;
+
+short word_378CC; //TODO: set by CLComputer_Init to 0
+short word_378CE;
+
+void RemoveConsole()
+{
+}
+void scroll()
+{
+ restaurefrises();
+ p_mainview->norm.src_left = scroll_pos;
+ p_mainview->zoom.src_left = scroll_pos;
+
+}
+void resetscroll()
+{
+ old_scroll_pos = scroll_pos;
+ scroll_pos = 0;
+ restaurefrises(); //TODO: inlined scroll() ?
+ p_mainview->norm.src_left = 0;
+ p_mainview->zoom.src_left = 0;
+}
+void scrollfresques()
+{
+ if(curs_y > 16 && curs_y < 176)
+ {
+ if(curs_x >= 0 && curs_x < 32 && scroll_pos > 3)
+ {
+ scroll_pos -= 4;
+ }
+ else if(curs_x > 288 && curs_x < 320 && scroll_pos < p_global->fresqWidth)
+ {
+ scroll_pos += 4;
+ }
+ }
+ scroll();
+
+}
+void afffresques()
+{
+ use_bank(p_global->fresqImgBank);
+ noclipax(0, 0, 16);
+ use_bank(p_global->fresqImgBank + 1);
+ noclipax(0, 320, 16);
+ needPaletteUpdate = 1;
+}
+void gametofresques()
+{
+ fresqTalk = 0;
+ rundcurs();
+ sauvefrises();
+ afffresques();
+ p_global->displayFlags = DisplayFlags::dfFresques;
+}
+void dofresques()
+{
+ curs_saved = 0;
+ torchCursor = 1;
+ glow_x = -1;
+ glow_y = -1;
+ p_global->gameFlags |= GameFlags::gfFlag20;
+ p_global->ff_D4 = 0;
+ p_global->curObjectId = 0;
+ p_global->iconsIndex = 13;
+ p_global->autoDialog = 0;
+ gametofresques();
+ p_global->fresqNumber = 3;
+}
+void finfresques()
+{
+ torchCursor = 0;
+ curs_saved = 1;
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ resetscroll();
+ p_global->ff_100 = -1;
+ maj_salle(p_global->roomNum);
+ if(p_global->phaseNum == 114)
+ p_global->narratorSequence = 1;
+ p_global->eventType = EventType::etEvent8;
+ showevents();
+}
+void scrollmiroir()
+{
+ if(curs_y > 16 && curs_y < 165)
+ {
+ if(curs_x >= 0 && curs_x < 16)
+ {
+ if(scroll_pos > 3)
+ {
+ if(doubled)
+ scroll_pos -= 2;
+ else
+ scroll_pos -= 1;
+ scroll();
+ }
+ }
+ else if(curs_x > 290 && curs_x < 320)
+ {
+ if(scroll_pos < 320)
+ {
+ if(doubled)
+ scroll_pos += 2;
+ else
+ scroll_pos += 1;
+ scroll();
+ }
+ }
+ }
+}
+void scrollpano()
+{
+ if(curs_y > 16 && curs_y < 165)
+ {
+ if(curs_x >= 0 && curs_x < 16)
+ {
+ if(scroll_pos > 3)
+ {
+ if(doubled)
+ scroll_pos -= 2;
+ else
+ scroll_pos -= 1;
+ }
+ }
+ else if(curs_x > 290 && curs_x < 320)
+ {
+ if(scroll_pos < 320)
+ {
+ if(doubled)
+ scroll_pos += 2;
+ else
+ scroll_pos += 1;
+ }
+ }
+ }
+ scroll();
+}
+void affsuiveur(suiveur_t *suiveur, short x, short y)
+{
+ use_bank(suiveur->bank);
+ noclipax(suiveur->image, x, y + 16);
+}
+void persoinmiroir()
+{
+ icon_t *icon1 = &gameIcons[3];
+ icon_t *icon = &gameIcons[28];
+ suiveur_t *suiveur = suiveurs_list;
+ short num = 1;
+ int i;
+ for(i = 0;i < 16;i++)
+ {
+ if(p_global->party & (1 << i))
+ num++;
+ }
+ icon += num;
+ icon->sx = -1;
+ icon--;
+ icon->sx = icon1->sx;
+ icon->sy = icon1->sy;
+ icon->ex = icon1->ex;
+ icon->ey = 170;
+ icon->cursor_id = icon1->cursor_id;
+ icon->action_id = icon1->action_id;
+ icon->object_id = icon1->object_id;
+ icon--;
+ affsuiveur(suiveur, suiveur->sx, suiveur->sy);
+ for(;suiveur->id != -1;suiveur++)
+ {
+ perso_t *perso;
+ for(perso = kPersons;perso != &kPersons[PER_UNKN_156];perso++)
+ {
+ if (perso->id != suiveur->id) continue;
+ if (perso->flags & PersonFlags::pf80) continue;
+ if ((perso->flags & PersonFlags::pfInParty) == 0) continue;
+ if (perso->roomNum != p_global->roomNum) continue;
+ icon->sx = suiveur->sx;
+ icon->sy = suiveur->sy;
+ icon->ex = suiveur->ex;
+ icon->ey = suiveur->ey;
+ icon->cursor_id = 8;
+ icon->action_id = perso->actionId;
+ icon--;
+ affsuiveur(suiveur, suiveur->sx, suiveur->sy);
+ break;
+ }
+ }
+}
+void gametomiroir(unsigned char arg1)
+{
+ short bank;
+ if(p_global->displayFlags != DisplayFlags::dfFlag2)
+ {
+ rundcurs();
+ restaurefrises();
+ afftopscr();
+ showobjects();
+ sauvefrises();
+ }
+ bank = p_global->roomBgBankNum;
+ if(bank == 76 || bank == 128)
+ bank = 2161;
+ use_bank(bank + 326);
+ noclipax(0, 0, 16);
+ use_bank(bank + 327);
+ noclipax(0, 320, 16);
+ persoinmiroir();
+ needPaletteUpdate = 1;
+ p_global->iconsIndex = 16;
+ p_global->autoDialog = 0;
+ p_global->displayFlags = DisplayFlags::dfMirror;
+ p_global->ff_102 = arg1;
+}
+void flipmode()
+{
+ if(personTalking)
+ {
+ endpersovox();
+ if(p_global->displayFlags == DisplayFlags::dfPerson)
+ {
+ if(p_global->perso_ptr == &kPersons[PER_THOO] && p_global->phaseNum >= 80)
+ af_subtitle();
+ else
+ {
+ getdatasync();
+ load_perso_cour();
+ addanim();
+ restartAnimation = 1;
+ anim_perso();
+ }
+ }
+ else
+ af_subtitle();
+ persovox();
+ }
+ else
+ {
+ if(p_global->displayFlags != DisplayFlags::dfFresques && p_global->displayFlags != DisplayFlags::dfFlag2)
+ {
+ closesalle();
+ if(p_global->displayFlags & DisplayFlags::dfFlag1)
+ gametomiroir(1);
+ else
+ {
+ quitmiroir();
+ maj_salle(p_global->roomNum);
+ if(byte_31D64)
+ {
+ dialautoon();
+ parle_moi();
+ }
+ byte_31D64 = 0;
+ }
+ }
+ }
+}
+void quitmiroir()
+{
+ rundcurs();
+ afficher();
+ resetscroll();
+ sauvefrises();
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ p_global->ff_100 = -1;
+ p_global->eventType = EventType::etEventC;
+ p_global->ff_102 = 1;
+}
+void clictimbre()
+{
+ flipmode();
+}
+void clicplanval()
+{
+ if((p_global->partyOutside & PersonMask::pmDina) && p_global->phaseNum == 371)
+ {
+ quitmiroir();
+ maj_salle(p_global->roomNum);
+ return;
+ }
+ if(p_global->roomNum == 8 || p_global->roomNum < 16)
+ return;
+ rundcurs();
+ afficher();
+ if(p_global->displayFlags == DisplayFlags::dfMirror)
+ quitmiroir();
+ deplaval((p_global->roomNum & 0xFF00) | 1); //TODO: check me
+}
+void gotolieu(goto_t *go)
+{
+ p_global->valleyVidNum = go->arriveVid;
+ p_global->travelTime = go->travelTime * 256;
+ p_global->stepsToFindAppleFast = 0;
+ p_global->eventType = EventType::etEvent2;
+ init_oui();
+ showevents();
+ if(!verif_oui())
+ return;
+ if(p_global->ff_113)
+ {
+ waitendspeak();
+ if(!pomme_q)
+ close_perso();
+ }
+ if(go->departVid)
+ {
+ bars_out();
+ playhnm(go->departVid);
+ needToFade = 1;
+ }
+ initlieu(p_global->newRoomNum);
+ specialoutside();
+ faire_suivre(p_global->newRoomNum);
+ closesalle();
+ saved_repadam.x = -1;
+ saved_repadam.y = -1;
+ temps_passe(p_global->travelTime);
+ p_global->ff_100 = p_global->room_ptr->ff_0;
+ p_global->roomNum = p_global->newRoomNum;
+ p_global->areaNum = p_global->roomNum >> 8;
+ p_global->eventType = EventType::etEvent5;
+ p_global->newMusicType = MusicType::mt2;
+ setpersohere();
+ musique();
+ majsalle1(p_global->roomNum);
+ afftopscr();
+ saved_repadam.x = -1;
+ saved_repadam.y = -1;
+}
+void deplaval(unsigned short roomNum)
+{
+ unsigned char c1, newAreaNum, curAreaNum;
+ short newRoomNum;
+ p_global->newLocation = roomNum & 0xFF;
+ p_global->valleyVidNum = 0;
+ p_global->phaseActionsCount++;
+ closesalle();
+ endpersovox();
+ c1 = roomNum & 0xFF;
+ if(c1 == 0)
+ return;
+ if(c1 < 0x80)
+ {
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ init_oui();
+ p_global->eventType = EventType::etEvent1;
+ showevents();
+ if(!verif_oui())
+ return;
+ if(p_global->ff_113)
+ {
+ waitendspeak();
+ if(!pomme_q)
+ close_perso();
+ }
+ specialout();
+ if(p_global->area_ptr->type == AreaType::atValley)
+ {
+ temps_passe(32);
+ p_global->stepsToFindAppleFast++;
+ p_global->stepsToFindAppleNormal++;
+ }
+ faire_suivre((roomNum & 0xFF00) | p_global->newLocation);
+ p_global->ff_100 = p_global->room_ptr->ff_0;
+ p_global->roomNum = roomNum;
+ p_global->areaNum = roomNum >> 8;
+ p_global->eventType = EventType::etEvent5;
+ setpersohere();
+ p_global->newMusicType = MusicType::mtNormal;
+ musique();
+ majsalle1(roomNum);
+ p_global->chrono_on = 0;
+ p_global->chrono = 0;
+ p_global->ff_54 = 0;
+ if(p_global->roomPersoType == PersonFlags::pftTyrann)
+ chronoon(3000);
+ return;
+ }
+ if(c1 == 0xFF)
+ {
+ p_global->eventType = EventType::etEventE;
+ showevents();
+ if(!kPersons[PER_MESSAGER].roomNum)
+ {
+ if(eloirevientq())
+ chronoon(800);
+ }
+ return;
+ }
+ p_global->stepsToFindAppleFast = 0;
+ newAreaNum = c1 & 0x7F;
+ curAreaNum = p_global->roomNum >> 8;
+ newRoomNum = newAreaNum << 8;
+ if(curAreaNum == Areas::arTausCave && newAreaNum == Areas::arMo)
+ newRoomNum |= 0x16;
+ else if(curAreaNum == Areas::arMoorkusLair)
+ newRoomNum |= 4;
+ else
+ newRoomNum |= 1;
+ p_global->newRoomNum = newRoomNum;
+ if(newAreaNum == Areas::arTausCave)
+ gotolieu(&gotos[0]);
+ else
+ {
+ goto_t *go;
+ for(go = gotos + 1;go->curAreaNum != 0xFF;go++)
+ if(go->curAreaNum == curAreaNum)
+ {
+ gotolieu(go);
+ break;
+ }
+ }
+}
+void deplacement(short dir)
+{
+ room_t *room = p_global->room_ptr;
+ short roomNum = p_global->roomNum;
+ debug("deplacement: from room %4X", roomNum);
+ char newLoc;
+ rundcurs();
+ afficher();
+ p_global->prevLocation = roomNum & 0xFF;
+ switch(dir)
+ {
+ case 0: newLoc = room->exits[0]; break;
+ case 1: newLoc = room->exits[1]; break;
+ case 2: newLoc = room->exits[2]; break;
+ case 3: newLoc = room->exits[3]; break;
+ }
+ deplaval((roomNum & 0xFF00) | newLoc);
+}
+void deplacement2(short dir)
+{
+ room_t *room = p_global->room_ptr;
+ short roomNum = p_global->roomNum;
+ char newLoc;
+ p_global->prevLocation = roomNum & 0xFF;
+ switch(dir)
+ {
+ case 0: newLoc = room->exits[0]; break;
+ case 1: newLoc = room->exits[1]; break;
+ case 2: newLoc = room->exits[2]; break;
+ case 3: newLoc = room->exits[3]; break;
+ }
+ deplaval((roomNum & 0xFF00) | newLoc);
+
+}
+void dinosoufle()
+{
+ if(p_global->curObjectId == 0)
+ {
+ bars_out();
+ playhnm(148);
+ maj2();
+ }
+}
+void plaquemonk()
+{
+ if(p_global->curObjectId != 0)
+ {
+ if(p_global->curObjectId == Objects::obPrism)
+ {
+ loseobject(Objects::obPrism);
+ bars_out();
+ specialTextMode = 1;
+ playhnm(89);
+ word_2F514 |= 0x8000;
+ maj2();
+ p_global->eventType = EventType::etEventB;
+ showevents();
+ }
+ }
+ else
+ {
+ bars_out();
+ playhnm(7);
+ maj2();
+ p_global->eventType = EventType::etEvent4;
+ showevents();
+ }
+}
+void fresquesgraa()
+{
+ if(p_global->curObjectId == 0)
+ {
+ p_global->fresqWidth = 320;
+ p_global->fresqImgBank = 113;
+ dofresques();
+ dinaparle();
+ }
+}
+void fresqueslasc()
+{
+ if(p_global->curObjectId == 0)
+ {
+ p_global->fresqWidth = 112;
+ p_global->fresqImgBank = 315;
+ dofresques();
+ }
+}
+void pushpierre()
+{
+ if(p_global->curObjectId == 0)
+ {
+ gameRooms[22].exits[0] = 17;
+ gameRooms[26].exits[2] = 9;
+ deplacement(0);
+ }
+}
+void tetemomie()
+{
+ if(p_global->curObjectId == Objects::obTooth)
+ {
+ p_global->gameFlags |= GameFlags::gfMummyOpened;
+ deplacement(0);
+ }
+ else if(p_global->curObjectId == 0)
+ {
+ if(p_global->gameFlags & GameFlags::gfMummyOpened)
+ deplacement(0);
+ else
+ {
+ p_global->eventType = EventType::etEvent6;
+ persoparle(PersonId::pidMonk);
+ p_global->eventType = 0;
+ }
+ }
+}
+void tetesquel()
+{
+ if(p_global->curObjectId == Objects::obTooth)
+ {
+ gameRooms[22].exits[0] = 16;
+ gameRooms[26].exits[2] = 13;
+ gameIcons[16].cursor_id |= 0x8000;
+ loseobject(Objects::obTooth);
+ deplacement(0);
+ }
+}
+void squelmoorkong()
+{
+ p_global->eventType = EventType::etEvent9;
+ showevents();
+}
+void choisir()
+{
+ unsigned char obj, objid = current_spot2->object_id;
+ switch(objid)
+ {
+ case 0: obj = p_global->giveobj1; break;
+ case 1: obj = p_global->giveobj2; break;
+ case 2: obj = p_global->giveobj3; break;
+ }
+ objectmain(obj);
+ winobject(obj);
+ p_global->iconsIndex = 16;
+ p_global->autoDialog = 0;
+ p_global->ff_60 = 0;
+ parle_moi();
+}
+void dinaparle()
+{
+ short num;
+ char res;
+ perso_t *perso = &kPersons[PER_DINA];
+ if(perso->party & (p_global->party | p_global->partyOutside))
+ {
+ if(p_global->fresqNumber < 3)
+ p_global->fresqNumber = 3;
+ p_global->fresqNumber++;
+ if(p_global->fresqNumber < 15)
+ {
+ endpersovox();
+ if(p_global->fresqNumber == 7 && p_global->phaseNum == 113)
+ incphase1();
+ p_global->perso_ptr = perso;
+ p_global->dialogType = DialogType::dtInspect;
+ num = (perso->id << 3) | DialogType::dtInspect; //TODO: combine
+ res = dialoscansvmas((dial_t*)GetElem(gameDialogs, num));
+ fresqTalk = 0;
+ if(res)
+ {
+ restaurefondbulle();
+ fresqTalk = 1;
+ persovox();
+ }
+ p_global->ff_CA = 0;
+ p_global->dialogType = 0;
+ }
+ else
+ finfresques();
+ }
+}
+void roiparle()
+{
+ if(p_global->phaseNum <= 400)
+ persoparle(0);
+}
+void roiparle1()
+{
+ if(p_global->curObjectId == Objects::obSword)
+ {
+ p_global->gameFlags |= GameFlags::gfFlag80;
+ bars_out();
+ playhnm(76);
+ deplacement2(0);
+ }
+ else
+ {
+ p_global->fresqNumber = 1;
+ roiparle();
+ }
+}
+void roiparle2()
+{
+ p_global->fresqNumber = 2;
+ roiparle();
+}
+void roiparle3()
+{
+ p_global->fresqNumber = 3;
+ roiparle();
+}
+void getcouteau()
+{
+ if(p_global->phaseNum >= 80)
+ {
+ gameRooms[113].video = 0;
+ getobject(Objects::obKnife);
+ }
+ p_global->eventType = EventType::etEvent7;
+ showevents();
+}
+void getprisme()
+{
+ getobject(Objects::obPrism);
+ p_global->eventType = EventType::etEvent7;
+ showevents();
+}
+void getchampb()
+{
+ getobject(Objects::obShroom);
+}
+void getchampm()
+{
+ getobject(Objects::obBadShroom);
+}
+void getor()
+{
+ getobject(Objects::obGold);
+}
+void getnido()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ p_global->room_ptr->bank = 282; //TODO: fix me
+ p_global->room_ptr--;
+ p_global->room_ptr->bank = 281; //TODO: fix me
+ p_global->room_ptr->ff_0 = 3;
+ getobject(Objects::obFullNest);
+}
+void getnidv()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ p_global->room_ptr->bank = 282; //TODO: fix me
+ p_global->room_ptr--;
+ p_global->room_ptr->bank = 281; //TODO: fix me
+ p_global->room_ptr->ff_0 = 3;
+ getobject(Objects::obNest);
+}
+void getcorne()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ getobject(Objects::obHorn);
+ p_global->eventType = EventType::etEvent7;
+ showevents();
+ bigphase1();
+ setpersohere();
+ p_global->room_ptr = getsalle(p_global->roomNum);
+}
+void getsoleil()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ gameRooms[238].video = 0;
+ gameRooms[238].flags = RoomFlags::rf80;
+ getobject(Objects::obSunStone);
+}
+void getoeuf()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ p_global->room_ptr->flags = 0;
+ p_global->room_ptr->video = 0;
+ getobject(Objects::obEgg);
+}
+void getplaque()
+{
+ int i;
+ if(p_global->curObjectId != 0 && p_global->curObjectId < Objects::obTablet1)
+ return;
+ p_global->curObjectId = 0;
+ getobject(Objects::obTablet2);
+ putobject();
+ for(i = 0;i < 6;i++)
+ objects[Objects::obTablet1 - 1 + i].count = 0;
+ p_global->curObjectFlags = 0;
+ p_global->inventoryScrollPos = 0;
+ p_global->curObjectCursor = 9;
+ gameIcons[16].cursor_id |= 0x8000;
+ showobjects();
+ gameRooms[131].video = 0;
+ bars_out();
+ playhnm(149);
+ p_global->ff_F1 = RoomFlags::rf04;
+ p_global->drawFlags = DrawFlags::drDrawFlag20;
+ normalCursor = 1;
+ maj2();
+}
+void voirlac()
+{
+ perso_t *perso = &kPersons[PER_MORKUS];
+ room_t *room = p_global->room_ptr;
+ area_t *area = p_global->area_ptr;
+ short vid = p_global->curObjectId == Objects::obApple ? 81 : 54;
+ for(++perso;perso->roomNum != 0xFFFF;perso++)
+ {
+ if(perso->roomNum != p_global->roomNum)
+ continue;
+ vid++;
+ if (p_global->curObjectId != Objects::obApple)
+ continue; //TODO: pc breaks here
+ if((perso->flags & PersonFlags::pfTypeMask) != PersonFlags::pftMosasaurus)
+ continue;
+ if (!(perso->flags & PersonFlags::pf80))
+ return;
+ perso->flags &= ~PersonFlags::pf80; //TODO: useless? see above
+ area->flags |= AreaFlags::afFlag8;
+ p_global->curAreaFlags |= AreaFlags::afFlag8;
+ room->ff_0 = 3;
+ }
+ debug("sea monster: room = %X, d0 = %X\n", p_global->roomNum, p_global->roomImgBank);
+ bars_out();
+ playhnm(vid);
+ maj_salle(p_global->roomNum); //TODO: getting memory trashed here?
+ if (p_global->curObjectId == Objects::obApple)
+ loseobject(Objects::obApple);
+ p_global->eventType = EventType::etEventF;
+ showevents();
+}
+void gotohall()
+{
+ p_global->prevLocation = p_global->roomNum & 0xFF;
+ deplaval((p_global->roomNum & 0xFF00) | 6);
+}
+void demitourlabi()
+{
+ unsigned short target;
+ p_global->prevLocation = p_global->roomNum & 0xFF;
+ p_global->ff_100 = -1;
+ target = (p_global->roomNum & 0xFF00) | p_global->room_ptr->exits[2];
+ faire_suivre(target);
+ p_global->roomNum = target;
+ p_global->eventType = EventType::etEvent5;
+ maj_salle(p_global->roomNum);
+}
+void gotonido()
+{
+ p_global->room_ptr++;
+ p_global->eventType = 0;
+ p_global->roomImgBank = p_global->room_ptr->bank;
+ p_global->roomVidNum = p_global->room_ptr->video;
+ p_global->curRoomFlags = p_global->room_ptr->flags;
+ p_global->ff_F1 = p_global->room_ptr->flags;
+ animpiece();
+ p_global->ff_100 = 0;
+ maj2();
+}
+void gotoval()
+{
+ unsigned short target = p_global->roomNum;
+ char obj;
+ rundcurs();
+ afficher();
+ scroll_pos = 0;
+ obj = current_spot2->object_id - 14; //TODO
+ p_global->prevLocation = target & 0xFF;
+ deplaval((target & 0xFF00) | obj); //TODO careful!
+}
+void visiter()
+{
+ bars_out();
+ playhnm(144);
+ p_global->ff_F1 = RoomFlags::rf04;
+ maj2();
+}
+void final()
+{
+ if(p_global->curObjectId != 0)
+ return;
+ bars_out();
+ *(short*)(gameRooms + 0x6DC) = 319; //TODO
+ p_global->roomImgBank = 319;
+ playhnm(97);
+ maj2();
+ p_global->eventType = EventType::etEvent12;
+ showevents();
+ p_global->narratorSequence = 54;
+}
+void goto_nord()
+{
+ if(p_global->curObjectId == 0)
+ deplacement(0);
+}
+void goto_est()
+{
+ if(p_global->curObjectId == 0)
+ deplacement(1);
+}
+void goto_sud()
+{
+ if(p_global->curObjectId == 0)
+ deplacement(2);
+}
+void goto_ouest()
+{
+ if(p_global->curObjectId == 0)
+ deplacement(3);
+}
+void afficher()
+{
+ if(!p_global->ff_102 && !p_global->ff_103)
+ {
+ if(needPaletteUpdate)
+ {
+ needPaletteUpdate = 0;
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ }
+ CLBlitter_CopyView2Screen(p_mainview);
+ }
+ else
+ {
+ if(p_global->ff_102)
+ effet3();
+ else
+ effet2();
+ p_global->ff_103 = 0;
+ p_global->ff_102 = 0;
+ }
+}
+void afficher128()
+{
+ if(p_global->updatePaletteFlag == 16)
+ {
+ CLPalette_Send2Screen(global_palette, 0, 129);
+ CLBlitter_CopyView2Screen(p_mainview);
+ p_global->updatePaletteFlag = 0;
+ }
+ else
+ {
+ ClearScreen();
+ fadetoblack128(1);
+ if(showBlackBars)
+ blackbars();
+ CLBlitter_CopyView2Screen(p_mainview);
+ fadefromblack128(1);
+ }
+}
+void sauvefrises()
+{
+ sauvefriseshaut(0);
+ sauvefrisesbas();
+}
+void sauvefriseshaut(short x) // Save top bar
+{
+ underTopBarScreenRect.sy = 0; //TODO: wrong fields order?
+ underTopBarScreenRect.sx = x;
+ underTopBarScreenRect.ex = x + 320 - 1;
+ underTopBarScreenRect.ey = 15;
+ underTopBarBackupRect.sy = 0;
+ underTopBarBackupRect.sx = 0;
+ underTopBarBackupRect.ex = 320 - 1;
+ underTopBarBackupRect.ey = 15;
+ CLBlitter_CopyViewRect(p_mainview, p_underBarsView, &underTopBarScreenRect, &underTopBarBackupRect);
+}
+void sauvefrisesbas() // Save bottom bar
+{
+ underBottomBarScreenRect.sx = 0;
+ underBottomBarScreenRect.ex = 320 - 1;
+ CLBlitter_CopyViewRect(p_mainview, p_underBarsView, &underBottomBarScreenRect, &underBottomBarBackupRect);
+}
+void restaurefrises()
+{
+ restaurefriseshaut();
+ restaurefrisesbas();
+}
+void restaurefriseshaut()
+{
+ underTopBarScreenRect.sx = scroll_pos;
+ underTopBarScreenRect.ex = scroll_pos + 320 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underTopBarBackupRect, &underTopBarScreenRect);
+}
+void restaurefrisesbas()
+{
+ underBottomBarScreenRect.sx = scroll_pos;
+ underBottomBarScreenRect.ex = scroll_pos + 320 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underBottomBarBackupRect, &underBottomBarScreenRect);
+}
+void use_main_bank()
+{
+ bank_data_ptr = main_bank_buf;
+}
+void use_bank(short bank)
+{
+ if (bank > 2500)
+ debug("attempt to load bad bank %d", bank);
+ bank_data_ptr = bank_data_buf;
+ if(cur_bank_num != bank)
+ {
+ loadfile(bank, bank_data_buf);
+ verifh(bank_data_buf);
+ cur_bank_num = bank;
+ }
+}
+void sundcurs(short x, short y)
+{
+ unsigned char *scr, *keep = curs_keepbuf;
+ short w, h;
+ curs_keepx = x - 4;
+ curs_keepy = y - 4;
+ scr = p_mainview_buf + curs_keepx + curs_keepy * 640;
+ for(h = 48;h--;)
+ {
+ for(w = 48;w--;)
+ *keep++ = *scr++;
+ scr += 640 - 48;
+ }
+ curs_saved = 1;
+}
+void rundcurs()
+{
+ unsigned char *scr, *keep = curs_keepbuf;
+ short w, h;
+ scr = p_mainview_buf + curs_keepx + curs_keepy * 640;
+ if(!curs_saved || (curs_keepx == -1 && curs_keepy == -1)) //TODO ...
+ return;
+ for(h = 48;h--;)
+ {
+ for(w = 48;w--;)
+ *scr++ = *keep++;
+ scr += 640 - 48;
+ }
+
+}
+void noclipax(short index, short x, short y)
+{
+ unsigned char *pix = bank_data_ptr;
+ unsigned char *scr = p_mainview_buf + x + y * 640;
+ unsigned char h0, h1, mode;
+ short w, h;
+ if(cur_bank_num != 117 && !no_palette)
+ {
+ if(PLE16(pix) > 2)
+ readpalette(pix + 2);
+ }
+ pix += PLE16(pix);
+ pix += PLE16(pix + index * 2);
+ // short height:9
+ // short pad:6;
+ // short flag:1;
+ h0 = *pix++;
+ h1 = *pix++;
+ w = ((h1 & 1) << 8) | h0;
+ h = *pix++;
+ mode = *pix++;
+ debug("- draw sprite %d at %d:%d, %dx%d", index, x, y, w, h);
+ if (mode != 0xFF && mode != 0xFE)
+ return;
+ if(y + h > 200)
+ h -= (y + h - 200);
+ if(h1 & 0x80)
+ {
+ // compressed
+ for(;h-- > 0;)
+ {
+ short ww;
+ for(ww = w;ww > 0;)
+ {
+ unsigned char c = *pix++;
+ if(c >= 0x80)
+ {
+ if(c == 0x80)
+ {
+ unsigned char fill = *pix++;
+ if(fill == 0)
+ {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ }
+ else
+ {
+ unsigned char run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for(run = 127;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char fill = *pix++;
+ unsigned char run = 255 - c + 2;
+ ww -= run;
+ if(fill == 0)
+ scr += run;
+ else
+ for(;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char run = c + 1;
+ ww -= run;
+ for(;run--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ }
+ else
+ {
+ // uncompressed
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+}
+void noclipax_avecnoir(short index, short x, short y)
+{
+ unsigned char *pix = bank_data_ptr;
+ unsigned char *scr = p_mainview_buf + x + y * 640;
+ unsigned char h0, h1, mode;
+ short w, h;
+ if(cur_bank_num != 117)
+ {
+ if(PLE16(pix) > 2)
+ readpalette(pix + 2);
+ }
+ pix += PLE16(pix);
+ pix += PLE16(pix + index * 2);
+ // short height:9
+ // short pad:6;
+ // short flag:1;
+ h0 = *pix++;
+ h1 = *pix++;
+ w = ((h1 & 1) << 8) | h0;
+ h = *pix++;
+ mode = *pix++;
+ if(mode != 0xFF && mode != 0xFE)
+ return;
+ if(y + h > 200)
+ h -= (y + h - 200);
+ if(h1 & 0x80)
+ {
+ // compressed
+ for(;h-- > 0;)
+ {
+ short ww;
+ for(ww = w;ww > 0;)
+ {
+ unsigned char c = *pix++;
+ if(c >= 0x80)
+ {
+ if(c == 0x80)
+ {
+ unsigned char fill = *pix++;
+ unsigned char run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for(run = 127;run--;)
+ *scr++ = fill;
+ }
+ else
+ {
+ unsigned char fill = *pix++;
+ unsigned char run = 255 - c + 2;
+ ww -= run;
+ for(;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char run = c + 1;
+ ww -= run;
+ for(;run--;)
+ {
+ unsigned char p = *pix++;
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ }
+ else
+ {
+ // uncompressed
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ {
+ unsigned char p = *pix++;
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+}
+void getglow(short x, short y, short w, short h)
+{
+ unsigned char *scr = p_mainview_buf + x + y * 640;
+ unsigned char *gl = glow_buffer;
+ glow_x = x;
+ glow_y = y;
+ glow_w = w;
+ glow_h = h;
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ *gl++ = *scr++;
+ scr += 640 - w;
+ }
+}
+void unglow()
+{
+ unsigned char *gl = glow_buffer;
+ unsigned char *scr = p_mainview_buf + glow_x + glow_y * 640;
+ if(glow_x < 0 || glow_y < 0) //TODO: move it up
+ return;
+ for(;glow_h--;)
+ {
+ short ww;
+ for(ww = glow_w;ww--;)
+ *scr++ = *gl++;
+ scr += 640 - glow_w;
+ }
+}
+void glow(short index)
+{
+ unsigned char pixbase;
+ unsigned char *pix = bank_data_ptr;
+ unsigned char *scr;
+ unsigned char h0, h1, mode;
+ short w, h, x, y, ex, dx, dy, pstride, sstride;
+ index += 9;
+ pix += PLE16(pix);
+ pix += PLE16(pix + index * 2);
+ // short height:9
+ // short pad:6;
+ // short flag:1;
+ h0 = *pix++;
+ h1 = *pix++;
+ w = ((h1 & 1) << 8) | h0;
+ h = *pix++;
+ mode = *pix++;
+ if(mode != 0xFF && mode != 0xFE)
+ return;
+
+ x = curs_x + scroll_pos - 38;
+ y = curs_y - 28;
+ ex = p_global->fresqWidth + 320;
+
+ if(x + w <= 0 || x >= ex || y + h <= 0 || y >= 176)
+ return;
+
+ if(x < 0)
+ {
+ dx = -x;
+ x = 0;
+ }
+ else if(x + w > ex)
+ dx = x + w - ex;
+ else
+ dx = 0;
+
+ if(y < 16)
+ {
+ dy = 16 - y;
+ y = 16;
+ }
+ else if(y + h > 175)
+ dy = y + h - 175;
+ else
+ dy = 0;
+ pstride = dx;
+ sstride = 640 - (w - dx);
+ if(y == 16)
+ pix += w * dy;
+ if(x == 0)
+ pix += dx;
+
+ scr = p_mainview_buf + x + y * 640;
+
+ w -= dx;
+ h -= dy;
+
+ getglow(x, y, w, h);
+
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ += p << 4;
+ }
+ pix += pstride;
+ scr += sstride;
+ }
+}
+void readpalette(unsigned char *ptr)
+{
+ int doit = 1;
+ while(doit)
+ {
+ unsigned short idx = *ptr++;
+ if(idx != 0xFF)
+ {
+ unsigned short cnt = *ptr++;
+ while(cnt--)
+ {
+ if(idx == 0)
+ {
+ pal_entry.r = 0;
+ pal_entry.g = 0;
+ pal_entry.b = 0;
+ ptr += 3;
+ }
+ else
+ {
+ pal_entry.r = *ptr++ << 10;
+ pal_entry.g = *ptr++ << 10;
+ pal_entry.b = *ptr++ << 10;
+ }
+ CLPalette_SetRGBColor(global_palette, idx, &pal_entry);
+ idx++;
+ }
+ }
+ else
+ doit = 0;
+ }
+}
+void spritesurbulle(short index, short x, short y)
+{
+ unsigned char *pix = bank_data_ptr;
+ unsigned char *scr = p_subtitlesview_buf + x + y * subtitles_x_width;
+ unsigned char h0, h1, mode;
+ short w, h;
+ if(cur_bank_num != 117)
+ {
+ if(PLE16(pix) > 2)
+ readpalette(pix + 2);
+ }
+ pix += PLE16(pix);
+ pix += PLE16(pix + index * 2);
+ // short height:9
+ // short pad:6;
+ // short flag:1;
+ h0 = *pix++;
+ h1 = *pix++;
+ w = ((h1 & 1) << 8) | h0;
+ h = *pix++;
+ mode = *pix++;
+ if(mode != 0xFF && mode != 0xFE)
+ return;
+ if(h1 & 0x80)
+ {
+ // compressed
+ for(;h-- > 0;)
+ {
+ short ww;
+ for(ww = w;ww > 0;)
+ {
+ unsigned char c = *pix++;
+ if(c >= 0x80)
+ {
+ if(c == 0x80)
+ {
+ unsigned char fill = *pix++;
+ if(fill == 0)
+ {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ }
+ else
+ {
+ unsigned char run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for(run = 127;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char fill = *pix++;
+ unsigned char run = 255 - c + 2;
+ ww -= run;
+ if(fill == 0)
+ scr += run;
+ else
+ for(;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char run = c + 1;
+ ww -= run;
+ for(;run--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += subtitles_x_width - w;
+ }
+ }
+ else
+ {
+ // uncompressed
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += subtitles_x_width - w;
+ }
+ }
+}
+void bars_out()
+{
+ short i, r19, r20, r25, r24;
+ unsigned int *scr40, *scr41, *scr42;
+ if(showBlackBars)
+ return;
+ afficher();
+ underTopBarScreenRect.sx = scroll_pos;
+ underTopBarScreenRect.ex = scroll_pos + 320 - 1;
+ CLBlitter_CopyViewRect(p_mainview, p_underBarsView, &underTopBarScreenRect, &underTopBarBackupRect);
+ underBottomBarScreenRect.sx = underTopBarScreenRect.sx;
+ underBottomBarScreenRect.ex = underTopBarScreenRect.ex;
+ CLBlitter_CopyViewRect(p_mainview, p_underBarsView, &underBottomBarScreenRect, &underBottomBarBackupRect);
+ r19 = 14; // TODO - init in decl?
+ r20 = 176;
+ r25 = 14;
+ r24 = 21;
+ underTopBarScreenRect.sx = 0;
+ underTopBarScreenRect.ex = 320 - 1;
+ underTopBarBackupRect.sx = scroll_pos;
+ underTopBarBackupRect.ex = scroll_pos + 320 - 1;
+ while(r24 > 0)
+ {
+ if(r25 > 0)
+ {
+ underTopBarScreenRect.sy = 16 - r25;
+ underTopBarScreenRect.ey = 16 - 1;
+ underTopBarBackupRect.sy = 0;
+ underTopBarBackupRect.ey = r25 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underTopBarScreenRect, &underTopBarBackupRect);
+ scr40 = ((unsigned int*)p_mainview_buf) + r19 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ for(i = 0;i < 320;i += 4)
+ {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ }
+ }
+ underTopBarScreenRect.sy = 16;
+ underTopBarScreenRect.ey = r24 + 16 - 1;
+ underTopBarBackupRect.sy = 200 - r24;
+ underTopBarBackupRect.ey = 200 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underTopBarScreenRect, &underTopBarBackupRect);
+ scr40 = ((unsigned int*)p_mainview_buf) + r20 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ scr42 = scr41 + 640 / 4;
+ for(i = 0;i < 320;i += 4)
+ {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ *scr42++ = 0;
+ }
+ r19 -= 2;
+ r20 += 3;
+ r25 -= 2;
+ r24 -= 3;
+ afficher();
+ }
+ scr40 = (unsigned int*)p_mainview_buf;
+ scr41 = scr40 + 640 / 4;
+ for(i = 0;i < 320;i += 4)
+ {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ }
+ scr40 = ((unsigned int*)p_mainview_buf) + r20 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ scr42 = scr41 + 640 / 4;
+ for(i = 0;i < 320;i += 4)
+ {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ *scr42++ = 0;
+ }
+ afficher();
+ initrect();
+ showBlackBars = 1;
+}
+void bars_in()
+{
+ short r29, r28;
+ if(!showBlackBars)
+ return;
+ blackbars();
+ r29 = 2;
+ r28 = 2;
+ underTopBarScreenRect.sx = 0;
+ underTopBarScreenRect.ex = 320 - 1;
+ underTopBarBackupRect.sx = scroll_pos;
+ underTopBarBackupRect.ex = scroll_pos + 320 - 1;
+ while(r28 < 24)
+ {
+ if(r29 <= 16)
+ {
+ underTopBarScreenRect.sy = 16 - r29;
+ underTopBarScreenRect.ey = 16 - 1;
+ underTopBarBackupRect.sy = 0;
+ underTopBarBackupRect.ey = r29 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underTopBarScreenRect, &underTopBarBackupRect);
+ }
+ underTopBarScreenRect.sy = 16;
+ underTopBarScreenRect.ey = 16 + r28;
+ underTopBarBackupRect.sy = 200 - 1 - r28;
+ underTopBarBackupRect.ey = 200 - 1;
+ CLBlitter_CopyViewRect(p_underBarsView, p_mainview, &underTopBarScreenRect, &underTopBarBackupRect);
+ r29 += 2;
+ r28 += 3;
+ afficher();
+ }
+ initrect();
+ showBlackBars = 0;
+}
+void sauvefondbouche()
+{
+ rect_src.sx = cur_perso_rect->sx;
+ rect_src.sy = cur_perso_rect->sy;
+ rect_src.ex = cur_perso_rect->ex;
+ rect_src.ey = cur_perso_rect->ey;
+ rect_dst.sx = cur_perso_rect->sx + 320;
+ rect_dst.sy = cur_perso_rect->sy;
+ rect_dst.ex = cur_perso_rect->ex + 320;
+ rect_dst.ey = cur_perso_rect->ey;
+ CLBlitter_CopyViewRect(p_mainview, p_mainview, &rect_src, &rect_dst);
+ fond_saved = 1;
+}
+void restaurefondbouche()
+{
+ rect_src.sx = cur_perso_rect->sx;
+ rect_src.sy = cur_perso_rect->sy;
+ rect_src.ex = cur_perso_rect->ex;
+ rect_src.ey = cur_perso_rect->ey;
+ rect_dst.sx = cur_perso_rect->sx + 320;
+ rect_dst.sy = cur_perso_rect->sy;
+ rect_dst.ex = cur_perso_rect->ex + 320;
+ rect_dst.ey = cur_perso_rect->ey;
+ CLBlitter_CopyViewRect(p_mainview, p_mainview, &rect_dst, &rect_src);
+}
+void blackbars()
+{
+ unsigned char *scr = p_mainview_buf;
+ short x, y;
+ for(y = 0;y < 16;y++)
+ for(x = 0;x < 640;x++)
+ *scr++ = 0;
+ scr += 640 * (200 - 16 - 24);
+ for(y = 0;y < 24;y++)
+ for(x = 0;x < 640;x++)
+ *scr++ = 0;
+}
+void afftopscr() // Draw top bar (location / party / map)
+{
+ perso_t *perso;
+ p_global->drawFlags &= ~DrawFlags::drDrawTopScreen;
+ use_bank(314);
+ noclipax(36, 83, 0);
+ noclipax(p_global->area_ptr->num - 1, 0, 0);
+ noclipax(23, 145, 0);
+ for(perso = &kPersons[PER_DINA];perso != &kPersons[PER_UNKN_156];perso++)
+ {
+ if ((perso->flags & PersonFlags::pfInParty) && !(perso->flags & PersonFlags::pf80))
+ noclipax(perso->targetLoc + 18, perso->lastLoc + 120, 0);
+ }
+ saved_repadam.x = -1;
+ saved_repadam.y = -1;
+ affplanval();
+ needPaletteUpdate = 1;
+}
+void affplanval() // Draw mini-map
+{
+ short loc;
+ perso_t *perso;
+ if(p_global->area_ptr->type == AreaType::atValley)
+ {
+ noclipax(p_global->area_ptr->num + 9, 266, 1);
+ for(perso = &kPersons[PER_UNKN_18C];perso->roomNum != 0xFFFF;perso++)
+ {
+ if(((perso->roomNum >> 8) == p_global->areaNum)
+ && !(perso->flags & PersonFlags::pf80) && (perso->flags & PersonFlags::pf20))
+ affrepere(33, perso->roomNum & 0xFF);
+ }
+ if(p_global->area_ptr->citadelLevel)
+ affrepere(34, p_global->area_ptr->citadelRoom->location);
+ sauvefriseshaut(0);
+ loc = p_global->roomNum & 0xFF;
+ if(loc >= 16)
+ affrepereadam(loc);
+ restaurefriseshaut();
+ }
+ else
+ {
+ sauvefriseshaut(0);
+ restaurefriseshaut();
+ }
+}
+void affrepere(short index, short location)
+{
+ noclipax(index, 269 + location % 16 * 4, 2 + (location - 16) / 16 * 3);
+}
+void affrepereadam(short location)
+{
+ short x = 269;
+ short y = 2;
+ short w;
+ unsigned char *pix;
+ rest_repadam();
+ if(location > 15 && location < 76)
+ {
+ x += (location & 15) * 4;
+ y += ((location - 16) >> 4) * 3;
+ save_repadam(x, y);
+ pix = p_underBarsView->p_buffer;
+ w = p_underBarsView->width;
+ pix += x + w * y;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ pix += w;
+ pix[0] = 0xC3;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ pix[3] = 0xC3;
+ pix += w;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ }
+}
+void rest_repadam()
+{
+ short x, y, w;
+ unsigned char *pix;
+ if(saved_repadam.x == -1 && saved_repadam.y == -1)
+ return;
+ x = saved_repadam.x;
+ y = saved_repadam.y;
+ pix = p_underBarsView->p_buffer;
+ w = p_underBarsView->width;
+ pix += x + w * y;
+ pix[1] = keep01; //TODO keep is array?
+ pix[2] = keep02;
+ pix += w;
+ pix[0] = keep10;
+ pix[1] = keep11;
+ pix[2] = keep12;
+ pix[3] = keep13;
+ pix += w;
+ pix[1] = keep21;
+ pix[2] = keep22;
+}
+void save_repadam(short x, short y)
+{
+ short w;
+ unsigned char *pix;
+ saved_repadam.x = x;
+ saved_repadam.y = y;
+ pix = p_underBarsView->p_buffer;
+ w = p_underBarsView->width;
+ pix += x + w * y;
+ keep01 = pix[1];
+ keep02 = pix[2];
+ pix += w;
+ keep10 = pix[0];
+ keep11 = pix[1];
+ keep12 = pix[2];
+ keep13 = pix[3];
+ pix += w;
+ keep21 = pix[1];
+ keep22 = pix[2];
+}
+char istrice(short roomNum)
+{
+ char loc = roomNum & 0xFF;
+ short area = roomNum & 0xFF00;
+ perso_t *perso;
+ for(perso = &kPersons[PER_UNKN_18C];perso != &kPersons[PER_UNKN_372];perso++)
+ {
+ if ((perso->flags & PersonFlags::pf80) || (perso->flags & PersonFlags::pfTypeMask) != PersonFlags::pftTriceraptor)
+ continue;
+ if(perso->roomNum == (area | (loc - 16)))
+ return 1;
+ if(perso->roomNum == (area | (loc + 16)))
+ return 1;
+ if(perso->roomNum == (area | (loc - 1)))
+ return 1;
+ if(perso->roomNum == (area | (loc + 1)))
+ return 1;
+ }
+ return 0;
+}
+char istyran(short roomNum)
+{
+ char loc = roomNum & 0xFF;
+ short area = roomNum & 0xFF00;
+ // TODO: orig bug: this ptr is not initialized when first called from getsalle
+ // PC version scans kPersons[] directly and is not affected
+ if (!tyranPtr)
+ return 0;
+
+ for(;tyranPtr->roomNum != 0xFFFF;tyranPtr++)
+ {
+ if (tyranPtr->flags & PersonFlags::pf80)
+ continue;
+ if(tyranPtr->roomNum == (area | (loc - 16)))
+ return 1;
+ if(tyranPtr->roomNum == (area | (loc + 16)))
+ return 1;
+ if(tyranPtr->roomNum == (area | (loc - 1)))
+ return 1;
+ if(tyranPtr->roomNum == (area | (loc + 1)))
+ return 1;
+ }
+ return 0;
+}
+void istyranval(area_t *area)
+{
+ perso_t *perso;
+ unsigned char areaNum = area->num;
+ area->flags &= ~AreaFlags::HasTyrann;
+ for(perso = &kPersons[PER_UNKN_372];perso->roomNum != 0xFFFF;perso++)
+ {
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ if((perso->roomNum >> 8) == areaNum)
+ {
+ area->flags |= AreaFlags::HasTyrann;
+ break;
+ }
+ }
+}
+char getdirection(perso_t *perso)
+{
+ char dir = -1;
+ unsigned char trgLoc = perso->targetLoc;
+ unsigned char curLoc = perso->roomNum & 0xFF; //TODO name
+ if(curLoc != trgLoc)
+ {
+ curLoc &= 0xF;
+ trgLoc &= 0xF;
+ if (curLoc != trgLoc)
+ {
+ dir = 2;
+ if (curLoc > trgLoc)
+ dir = 5;
+ }
+ trgLoc = perso->targetLoc;
+ curLoc = perso->roomNum & 0xFF;
+ curLoc &= 0xF0;
+ trgLoc &= 0xF0;
+ if (curLoc != trgLoc)
+ {
+ if (curLoc > trgLoc)
+ dir++;
+ dir++;
+ }
+ }
+ return dir;
+};
+char caselibre(char loc, perso_t *perso)
+{
+ short roomNum;
+ room_t *room = p_global->cita_area_firstRoom;
+ if(loc <= 0x10 || loc > 76 || (loc & 0xF) >= 12 || loc == perso->lastLoc)
+ return 0;
+ roomNum = (perso->roomNum & ~0xFF) | loc; //TODO: danger! signed
+ if(roomNum == p_global->roomNum)
+ return 0;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(room->location != loc)
+ continue;
+ if(!(room->flags & RoomFlags::rf01))
+ return 0;
+ for(perso = &kPersons[PER_UNKN_18C];perso->roomNum != 0xFFFF;perso++)
+ {
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ if(perso->roomNum == roomNum)
+ break;
+ }
+ if(perso->roomNum != 0xFFFF)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+void melange1(char elem[4])
+{
+ if (g_ed->_rnd->getRandomNumber(1) & 1)
+ {
+ char e1 = elem[1];
+ char e2 = elem[2];
+ elem[1] = e2;
+ elem[2] = e1;
+ }
+}
+void melange2(char elem[4])
+{
+ if (g_ed->_rnd->getRandomNumber(1) & 1)
+ {
+ char e0 = elem[0];
+ char e1 = elem[1];
+ elem[0] = e1;
+ elem[1] = e0;
+ }
+ if (g_ed->_rnd->getRandomNumber(1) & 1)
+ {
+ char e2 = elem[2];
+ char e3 = elem[3];
+ elem[2] = e3;
+ elem[3] = e2;
+ }
+}
+void melangedir()
+{
+ melange1(tab_2CB1E[0]);
+ melange1(tab_2CB1E[1]);
+ melange1(tab_2CB1E[2]);
+ melange2(tab_2CB1E[3]);
+ melange2(tab_2CB1E[4]);
+ melange1(tab_2CB1E[5]);
+ melange2(tab_2CB1E[6]);
+ melange2(tab_2CB1E[7]);
+}
+char naitredino(char persoType)
+{
+ perso_t *perso;
+ for(perso = &kPersons[PER_MORKUS];(++perso)->roomNum != 0xFFFF;)
+ {
+ char areaNum = perso->roomNum >> 8;
+ if(areaNum != p_global->cita_area_num)
+ continue;
+ if ((perso->flags & PersonFlags::pf80) && (perso->flags & PersonFlags::pfTypeMask) == persoType)
+ {
+ perso->flags &= ~PersonFlags::pf80;
+ return 1;
+ }
+ }
+ return 0;
+}
+void newcita(char arg1, short arg2, room_t *room)
+{
+ unsigned short index;
+ short *ptr;
+ cita_t *cita = cita_list;
+ while(cita->ff_0 < arg2)
+ cita++;
+ index = ((room->flags & 0xC0) >> 6); //TODO: this is very wrong
+ ptr = cita->ff_2 + index * 2;
+ if(arg1 == 4 || arg1 == 6)
+ ptr++;
+ room->bank = ptr[0];
+ room->video = ptr[8];
+ room->flags |= RoomFlags::rf02;
+}
+void citaevol(short level)
+{
+ room_t *room = p_global->cur_area_ptr->citadelRoom;
+ perso_t *perso = &kPersons[PER_UNKN_372];
+ unsigned char speed, loc = room->location;
+ if (level >= 80 && !istrice((p_global->cita_area_num << 8) | room->location)) //TODO: loc ?
+ {
+ room->level = 79;
+ return;
+ }
+ if(level > 160)
+ level = 160;
+ if(room->level < 64 && level >= 64 && naitredino(PersonFlags::pftTriceraptor))
+ {
+ p_global->cur_area_ptr->flags |= AreaFlags::HasTriceraptors;
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnTriceraptorsIn);
+ }
+ if(room->level < 40 && level >= 40 && naitredino(PersonFlags::pftVelociraptor))
+ {
+ p_global->cur_area_ptr->flags |= AreaFlags::HasVelociraptors;
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnVelociraptorsIn);
+ }
+ room->level = level;
+ newcita(p_global->cita_area_num, level, room);
+ speed = kDinoSpeedForCitaLevel[room->level >> 4];
+ for(;perso->roomNum != 0xFFFF;perso++)
+ {
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ if ((perso->roomNum >> 8) == p_global->cita_area_num && perso->targetLoc == loc)
+ perso->speed = speed;
+ }
+}
+void citacapoute(short roomNum)
+{
+ perso_t *perso = &kPersons[PER_UNKN_18C];
+ room_t *room = p_global->cur_area_ptr->citadelRoom;
+ room->flags |= RoomFlags::rf01;
+ room->flags &= ~RoomFlags::rfHasCitadel;
+ room->bank = 193;
+ room->video = 0;
+ room->level = 0;
+ p_global->cur_area_ptr->citadelLevel = 0;
+ p_global->cur_area_ptr->citadelRoom = 0;
+ roomNum = (roomNum & ~0xFF) | room->location;
+ for(;perso->roomNum != 0xFFFF;perso++)
+ {
+ if(perso->roomNum == roomNum)
+ {
+ perso->flags &= ~PersonFlags::pf80;
+ delinfo((roomNum >> 8) + ValleyNews::vnTyrannIn);
+ break;
+ }
+ }
+}
+void buildcita()
+{
+ area_t *area = p_global->area_ptr;
+ p_global->cur_area_ptr = p_global->area_ptr;
+ if(area->citadelRoom)
+ citacapoute(p_global->roomNum);
+ p_global->ff_6A = p_global->ff_69;
+ p_global->narratorSequence = p_global->ff_69 | 0x80;
+ area->citadelRoom = p_global->room_ptr;
+ p_global->room_ptr->flags &= ~RoomFlags::rf01;
+ p_global->room_ptr->flags |= RoomFlags::rfHasCitadel;
+ p_global->room_ptr->level = 32;
+ newcita(p_global->areaNum, 32, p_global->room_ptr);
+ area->flags &= ~AreaFlags::TyrannSighted;
+ if (!(area->flags & AreaFlags::afFlag8000))
+ {
+ if(p_global->phaseNum == 304 || p_global->phaseNum != 384) //TODO: wha
+ eloirevient();
+ area->flags |= AreaFlags::afFlag8000;
+ }
+ p_global->room_perso->flags |= PersonFlags::pf80;
+ p_global->cita_area_num = p_global->areaNum;
+ naitredino(1);
+ delinfo(p_global->areaNum + ValleyNews::vnCitadelLost);
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannLost);
+ if(p_global->phaseNum == 193 && p_global->areaNum == Areas::arUluru)
+ bigphase1();
+}
+void citatombe(char level)
+{
+ if(level)
+ newcita(p_global->cita_area_num, level, p_global->cur_area_ptr->citadelRoom);
+ else
+ {
+ citacapoute(p_global->cita_area_num << 8);
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnCitadelLost);
+ }
+}
+void constcita()
+{
+ unsigned char level;
+ room_t *room;
+ unsigned char loc;
+// room_t *room = p_global->cur_area_ptr->room_ptr; //TODO: wrong? chk below
+// unsigned char id = room->ff_C;
+ if(!p_global->cur_area_ptr->citadelLevel || !p_global->cur_area_ptr->citadelRoom)
+ return;
+ room = p_global->cur_area_ptr->citadelRoom; //TODO: copied here by me
+ loc = room->location;
+ tyranPtr = &kPersons[PER_UNKN_372];
+ if(istyran((p_global->cita_area_num << 8) | loc))
+ {
+ if(!(p_global->cur_area_ptr->flags & AreaFlags::TyrannSighted))
+ {
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnTyrannIn);
+ p_global->cur_area_ptr->flags |= AreaFlags::TyrannSighted;
+ }
+ level = room->level - 1;
+ if(level < 32)
+ level = 32;
+ room->level = level;
+ citatombe(level);
+ }
+ else
+ {
+ p_global->cur_area_ptr->flags &= ~AreaFlags::TyrannSighted;
+ citaevol(room->level + 1);
+ }
+}
+void depladino(perso_t *perso)
+{
+ char *dirs, dir, dir2;
+ unsigned char loc;
+ dir = getdirection(perso);
+ if(dir != -1)
+ {
+ melangedir();
+ dirs = tab_2CB1E[dir];
+ loc = perso->roomNum & 0xFF;
+ dir2 = *dirs++;
+ if(dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if(caselibre(dir2, perso))
+ goto ok;
+ dir2 = *dirs++;
+ if(dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (caselibre(dir2, perso))
+ goto ok;
+ dir2 = *dirs++;
+ if(dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (caselibre(dir2, perso))
+ goto ok;
+ dir2 = *dirs++;
+ if(dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (caselibre(dir2, perso))
+ goto ok;
+ dir2 = perso->lastLoc;
+ perso->lastLoc = 0;
+ if(!caselibre(dir2, perso))
+ return;
+ok:;
+ perso->lastLoc = perso->roomNum & 0xFF;
+ perso->roomNum &= ~0xFF;
+ perso->roomNum |= dir2 & 0xFF;
+ if(perso->targetLoc - 16 == (perso->roomNum & 0xFF))
+ perso->targetLoc = 0;
+ if(perso->targetLoc + 16 == (perso->roomNum & 0xFF))
+ perso->targetLoc = 0;
+ if(perso->targetLoc - 1 == (perso->roomNum & 0xFF))
+ perso->targetLoc = 0;
+ if(perso->targetLoc + 1 == (perso->roomNum & 0xFF))
+ perso->targetLoc = 0;
+ }
+ else
+ perso->targetLoc = 0;
+}
+void deplaalldino()
+{
+ perso_t *perso = &kPersons[PER_UNKN_18C - 1]; //TODO fix this
+ while((++perso)->roomNum != 0xFFFF)
+ {
+ if(((perso->roomNum >> 8) & 0xFF) != p_global->cita_area_num)
+ continue;
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ if(!perso->targetLoc)
+ continue;
+ if(--perso->steps)
+ continue;
+ perso->steps = 1;
+ if(perso->roomNum == p_global->roomNum)
+ continue;
+ perso->steps = perso->speed;
+ depladino(perso);
+ }
+}
+void newvallee()
+{
+ perso_t *perso = &kPersons[PER_UNKN_372];
+ short *ptr = tab_2CB16;
+ short roomNum;
+ while((roomNum = *ptr++) != -1)
+ {
+ perso->roomNum = roomNum;
+ perso->flags &= ~PersonFlags::pf80;
+ perso->flags &= ~PersonFlags::pf20; //TODO: combine?
+ perso++;
+ }
+ perso->roomNum = -1;
+ kAreasTable[7].flags |= AreaFlags::HasTyrann;
+ p_global->worldHasTyrann = 32;
+}
+char whereiscita()
+{
+ room_t *room = p_global->cita_area_firstRoom;
+ char res = -1;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(!(room->flags & RoomFlags::rfHasCitadel))
+ continue;
+ res = room->location;
+ break;
+ }
+ return res;
+}
+char iscita(short loc)
+{
+ room_t *room = p_global->cita_area_firstRoom;
+ loc &= 0xFF;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(!(room->flags & RoomFlags::rfHasCitadel))
+ continue;
+ if(room->location == loc + 16)
+ return 1;
+ if(room->location == loc - 16)
+ return 1;
+ if(room->location == loc - 1)
+ return 1;
+ if(room->location == loc + 1)
+ return 1;
+ }
+ return 0;
+}
+void lieuvava(area_t *area)
+{
+ unsigned char mask;
+ if(area->type == AreaType::atValley)
+ {
+ istyranval(area);
+ area->citadelLevel = 0;
+ if(area->citadelRoom)
+ area->citadelLevel = p_global->cita_area_firstRoom->level; //TODO: no search?
+ mask = ~(1 << (area->num - Areas::arChamaar));
+ p_global->worldTyrannSighted &= mask;
+ p_global->ff_4E &= mask;
+ p_global->worldGaveGold &= mask;
+ p_global->worldHasVelociraptors &= mask;
+ p_global->worldHasTriceraptors &= mask;
+ p_global->worldHasTyrann &= mask;
+ p_global->ff_53 &= mask;
+ mask = ~mask;
+ if(area->flags & AreaFlags::TyrannSighted)
+ p_global->worldTyrannSighted |= mask;
+ if(area->flags & AreaFlags::afFlag4)
+ p_global->ff_4E |= mask;
+ if(area->flags & AreaFlags::HasTriceraptors)
+ p_global->worldHasTriceraptors |= mask;
+ if(area->flags & AreaFlags::afGaveGold)
+ p_global->worldGaveGold |= mask;
+ if(area->flags & AreaFlags::HasVelociraptors)
+ p_global->worldHasVelociraptors |= mask;
+ if(area->flags & AreaFlags::HasTyrann)
+ p_global->worldHasTyrann |= mask;
+ if(area->flags & AreaFlags::afFlag20)
+ p_global->ff_53 |= mask;
+ if(area == p_global->area_ptr)
+ {
+ p_global->curAreaFlags = area->flags;
+ p_global->curCitadelLevel = area->citadelLevel;
+ }
+ }
+ p_global->ff_4D &= p_global->worldTyrannSighted;
+}
+void vivredino()
+{
+ char cita;
+ perso_t *perso = &kPersons[PER_UNKN_18C];
+ for(;perso->roomNum != 0xFFFF;perso++)
+ {
+ if(((perso->roomNum >> 8) & 0xFF) != p_global->cita_area_num)
+ continue;
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ switch(perso->flags & PersonFlags::pfTypeMask)
+ {
+ case PersonFlags::pftTyrann:
+ if(iscita(perso->roomNum))
+ perso->targetLoc = 0;
+ else if(!perso->targetLoc)
+ {
+ cita = whereiscita();
+ if(cita != -1)
+ {
+ perso->targetLoc = cita;
+ perso->speed = 2;
+ perso->steps = 1;
+ }
+ }
+ break;
+ case PersonFlags::pftTriceraptor:
+ if (perso->flags & PersonFlags::pfInParty)
+ {
+ if(iscita(perso->roomNum))
+ perso->targetLoc = 0;
+ else if(!perso->targetLoc)
+ {
+ cita = whereiscita();
+ if(cita != -1)
+ {
+ perso->targetLoc = cita;
+ perso->speed = 3;
+ perso->steps = 1;
+ }
+ }
+ }
+ break;
+ case PersonFlags::pftVelociraptor:
+ if (perso->flags & PersonFlags::pf10)
+ {
+ if(perso->roomNum == p_global->roomNum)
+ {
+ perso_t *perso2 = &kPersons[PER_UNKN_372];
+ char found = 0;
+ for(;perso2->roomNum != 0xFFFF;perso2++)
+ {
+ if((perso->roomNum & ~0xFF) == (perso2->roomNum & ~0xFF))
+ {
+ if (perso2->flags & PersonFlags::pf80)
+ continue;
+ perso->targetLoc = perso2->roomNum & 0xFF;
+ perso->steps = 1;
+ found = 1;
+ break;
+ }
+ }
+ if(found)
+ continue;
+ }
+ else
+ {
+ tyranPtr = &kPersons[PER_UNKN_372];
+ if(istyran(perso->roomNum))
+ {
+ if(p_global->phaseNum < 481 && (perso->powers & (1 << (p_global->cita_area_num - 3))))
+ {
+ tyranPtr->flags |= PersonFlags::pf80;
+ tyranPtr->roomNum = 0;
+ perso->flags &= ~PersonFlags::pf10;
+ perso->flags |= PersonFlags::pfInParty;
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnTyrannLost);
+ delinfo(p_global->cita_area_num + ValleyNews::vnTyrannIn);
+ if(naitredino(PersonFlags::pftTriceraptor))
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnTriceraptorsIn);
+ constcita();
+ p_global->cur_area_ptr->flags &= ~AreaFlags::TyrannSighted;
+ }
+ else
+ {
+ perso->flags &= ~PersonFlags::pf10;
+ perso->flags &= ~PersonFlags::pfInParty;
+ ajouinfo(p_global->cita_area_num + ValleyNews::vnVelociraptorsLost);
+ }
+ continue;
+ }
+ }
+ }
+ if(!perso->targetLoc)
+ {
+ short loc;
+ perso->lastLoc = 0;
+ do
+ {
+ loc = (g_ed->_rnd->getRandomNumber(63) & 63) + 16;
+ if((loc & 0xF) >= 12)
+ loc &= ~4; //TODO: ??? same as -= 4
+ }
+ while(!caselibre(loc, perso));
+ perso->targetLoc = loc;
+ perso->steps = 1;
+ }
+ break;
+ }
+ }
+}
+void vivreval(short areaNum)
+{
+ p_global->cita_area_num = areaNum;
+ p_global->cur_area_ptr = &kAreasTable[areaNum - 1];
+ p_global->cita_area_firstRoom = &gameRooms[p_global->cur_area_ptr->firstRoomIndex];
+ deplaalldino();
+ constcita();
+ vivredino();
+ newchampi();
+ newnido();
+ newnidv();
+ if(p_global->phaseNum >= 226)
+ newor();
+ lieuvava(p_global->cur_area_ptr);
+}
+void chaquejour()
+{
+ vivreval(3);
+ vivreval(4);
+ vivreval(5);
+ vivreval(6);
+ vivreval(7);
+ vivreval(8);
+ p_global->drawFlags |= DrawFlags::drDrawTopScreen;
+}
+void temps_passe(short t)
+{
+ short days = p_global->gameDays;
+ short lo = p_global->ff_56;
+ lo += t;
+ if(lo > 255)
+ {
+ days++;
+ lo &= 0xFF;
+ }
+ p_global->ff_56 = lo;
+ t = ((t >> 8) & 0xFF) + days;
+ t -= p_global->gameDays;
+ if(t)
+ {
+ p_global->gameDays += t;
+ while(t--)
+ chaquejour();
+ }
+}
+void heurepasse()
+{
+ temps_passe(5);
+}
+void anim_perso()
+{
+ if(cur_bank_num != p_global->perso_img_bank)
+ load_perso(p_global->perso_ptr);
+ restaurefondbulle();
+ if(restartAnimation)
+ {
+ last_anim_ticks = TimerTicks;
+ restartAnimation = 0;
+ }
+ cur_anim_frame_num = (TimerTicks - last_anim_ticks) >> 2; // TODO: check me!!!
+ if(cur_anim_frame_num > num_anim_frames) // TODO: bug?
+ animateTalking = 0;
+ if(p_global->curPersoAnimPtr && !p_global->animationFlags && cur_anim_frame_num != last_anim_frame_num)
+ {
+ last_anim_frame_num = cur_anim_frame_num;
+ if(*p_global->curPersoAnimPtr == 0xFF)
+ getanimrnd();
+ bank_data_ptr = perso_img_bank_data_ptr;
+ num_img_desc = 0;
+ perso_spr(p_global->curPersoAnimPtr);
+ p_global->curPersoAnimPtr += num_img_desc + 1;
+ dword_3072C = imagedesc + 200;
+ virespritebouche();
+ if(*dword_3072C)
+ af_image();
+ animationDelay--;
+ if(!animationDelay) //TODO: combine
+ {
+ p_global->animationFlags = 1;
+ animationDelay = 8;
+ }
+ }
+
+ animationDelay--;
+ if(!animationDelay) //TODO: combine
+ {
+ getanimrnd();
+ //TODO: no reload?
+ }
+ if(animateTalking)
+ {
+ if(!animationTable)
+ {
+ animationTable = gameLipsync + 7262; //TODO: fix me
+ if(!fond_saved)
+ sauvefondbouche();
+ }
+ if(!personTalking)
+ cur_anim_frame_num = num_anim_frames - 1;
+ animationIndex = animationTable[cur_anim_frame_num];
+ if(animationIndex == 0xFF)
+ animateTalking = 0;
+ else if(animationIndex != lastAnimationIndex)
+ {
+ bank_data_ptr = perso_img_bank_data_ptr;
+ restaurefondbouche();
+// debug("perso spr %d", animationIndex);
+ perso_spr(p_global->persoSpritePtr2 + animationIndex * 2); //TODO: shorts?
+ dword_3072C = imagedesc + 200;
+ if(*dword_3072C)
+ af_image();
+ lastAnimationIndex = animationIndex;
+ }
+ }
+ af_subtitle();
+}
+void getanimrnd()
+{
+ short rnd;
+ animationDelay = 8;
+ rnd = g_ed->_rnd->getRandomNumber(65535) & (unsigned char)~0x18; //TODO
+ dword_30724 = p_global->persoSpritePtr + 16; //TODO
+ p_global->curPersoAnimPtr = p_global->persoSpritePtr + ((dword_30724[1] << 8) + dword_30724[0]);
+ p_global->animationFlags = 1;
+ if(rnd >= 8)
+ return;
+ p_global->animationFlags = 0;
+ if(rnd <= 0)
+ return;
+ for(rnd *= 8;rnd > 0;rnd--)
+ {
+ while(*p_global->curPersoAnimPtr)
+ p_global->curPersoAnimPtr++;
+ p_global->curPersoAnimPtr++;
+ }
+}
+void addanim()
+{
+ lastAnimationIndex = -1;
+ last_anim_ticks = 0;
+ p_global->animationFlags = 0xC0;
+ p_global->curPersoAnimPtr = p_global->persoSpritePtr;
+ getanimrnd();
+ animationActive = 1;
+ if(p_global->perso_ptr == &kPersons[PER_ROI])
+ return;
+ perso_spr(p_global->persoSpritePtr + PLE16(p_global->persoSpritePtr)); //TODO: GetElem(0)
+ dword_3072C = imagedesc + 200;
+ if (p_global->perso_ptr->id != PersonId::pidCabukaOfCantura && p_global->perso_ptr->targetLoc != 7) //TODO: targetLoc is minisprite idx
+ virespritebouche();
+ if(*dword_3072C)
+ af_image();
+}
+void virespritebouche()
+{
+ unsigned char *src = dword_3072C + 2;
+ unsigned char *dst = src;
+ char cnt = dword_3072C[0];
+ while(cnt--)
+ {
+ unsigned char a = *src++;
+ unsigned char b = *src++;
+ unsigned char c = *src++;
+ dst[0] = a;
+ dst[1] = b;
+ dst[2] = c;
+ if(dword_30728[0] != 0xFF)
+ {
+ if((a < dword_30728[0] || a > dword_30728[1])
+ && (a < dword_30728[2] || a > dword_30728[3]))
+ dst += 3;
+ else
+ dword_3072C[0]--;
+ }
+ else
+ dst += 3;
+ }
+}
+void anim_perfin()
+{
+ p_global->animationFlags &= ~0x80;
+ animationDelay = 0;
+ animationActive = 0;
+}
+void perso_spr(unsigned char *spr)
+{
+ unsigned char *img = imagedesc + 200 + 2;
+ short count = 0;
+ unsigned char c, cc;
+ while((c = *spr++))
+ {
+ unsigned char *src;
+ short index;
+ cc = 0;
+ if(c == 1)
+ {
+ cc = index;
+ c = *spr++;
+ }
+ num_img_desc++;
+ index = (cc << 8) | c;
+ index -= 2;
+// debug("anim sprite %d", index);
+
+ if(index > max_perso_desc)
+ index = max_perso_desc;
+ index *= 2; //TODO: src = GetElem(ff_C2, index)
+ src = p_global->ff_C2;
+ src = src + PLE16(src + index);
+ while((c = *src++))
+ {
+ *img++ = c;
+ *img++ = *src++;
+ *img++ = *src++;
+ count++;
+ }
+ }
+ imagedesc[200] = count & 0xFF;
+ imagedesc[201] = count >> 8;
+}
+void af_image()
+{
+ unsigned char *img = imagedesc + 200, *img_start, *curimg = imagedesc;
+ short count;
+
+ count = PLE16(img);
+ if(!count)
+ return;
+ img_start = img;
+ img += 2;
+ count *= 3;
+ while(count--)
+ *curimg++ = *img++;
+ img = img_start;
+ count = PLE16(img); img += 2;
+/////// draw it
+ while(count--)
+ {
+ unsigned short index = *img++;
+ unsigned short x = *img++ + gameIcons[0].sx;
+ unsigned short y = *img++ + gameIcons[0].sy;
+ unsigned char *pix = bank_data_ptr;
+ unsigned char *scr = p_mainview_buf + x + y * 640;
+ unsigned char h0, h1, mode;
+ short w, h;
+ index--;
+ if(PLE16(pix) > 2)
+ readpalette(pix + 2);
+ pix += PLE16(pix);
+ pix += PLE16(pix + index * 2);
+ // short height:9
+ // short pad:6;
+ // short flag:1;
+ h0 = *pix++;
+ h1 = *pix++;
+ w = ((h1 & 1) << 8) | h0;
+ h = *pix++;
+ mode = *pix++;
+ if(mode != 0xFF && mode != 0xFE)
+ continue; //TODO: enclosing block?
+ if(h1 & 0x80)
+ {
+ // compressed
+ for(;h-- > 0;)
+ {
+ short ww;
+ for(ww = w;ww > 0;)
+ {
+ unsigned char c = *pix++;
+ if(c >= 0x80)
+ {
+ if(c == 0x80)
+ {
+ unsigned char fill = *pix++;
+ if(fill == 0)
+ {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ }
+ else
+ {
+ unsigned char run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for(run = 127;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char fill = *pix++;
+ unsigned char run = 255 - c + 2;
+ ww -= run;
+ if(fill == 0)
+ scr += run;
+ else
+ for(;run--;)
+ *scr++ = fill;
+ }
+ }
+ else
+ {
+ unsigned char run = c + 1;
+ ww -= run;
+ for(;run--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ }
+ else
+ {
+ // uncompressed
+ for(;h--;)
+ {
+ short ww;
+ for(ww = w;ww--;)
+ {
+ unsigned char p = *pix++;
+ if(p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+ }
+}
+void af_perso1()
+{
+ perso_spr(p_global->persoSpritePtr + PLE16(p_global->persoSpritePtr));
+ af_image();
+}
+void af_perso()
+{
+ load_perso_cour();
+ af_perso1();
+}
+void ef_perso()
+{
+ p_global->animationFlags &= 0x3F;
+}
+void load_perso(perso_t *perso)
+{
+ unsigned char *ptr, *baseptr;
+ perso_img_bank_data_ptr = 0;
+ if(!perso->bank)
+ return;
+ if(perso->bank != p_global->perso_img_bank)
+ {
+ cur_perso_rect = &perso_rects[perso->id]; //TODO: array of short?
+ dword_30728 = tab_persxx[perso->id];
+ ef_perso();
+ p_global->perso_img_bank = perso->bank;
+ use_bank(p_global->perso_img_bank);
+ perso_img_bank_data_ptr = bank_data_ptr;
+ ptr = bank_data_ptr;
+ ptr += PLE16(ptr);
+ baseptr = ptr;
+ ptr += PLE16(ptr) - 2;
+ ptr = baseptr + PLE16(ptr) + 4;
+ gameIcons[0].sx = PLE16(ptr);
+ gameIcons[0].sy = PLE16(ptr + 2);
+ gameIcons[0].ex = PLE16(ptr + 4);
+ gameIcons[0].ey = PLE16(ptr + 6);
+ ptr += 8;
+ p_global->ff_C2 = ptr + 2;
+ max_perso_desc = PLE16(ptr) / 2;
+ ptr += PLE16(ptr);
+ baseptr = ptr;
+ ptr += PLE16(ptr) - 2;
+ p_global->persoSpritePtr = baseptr;
+ p_global->persoSpritePtr2 = baseptr + PLE16(ptr);
+ debug("load perso: b6 len is %d", p_global->persoSpritePtr2 - p_global->persoSpritePtr);
+ }
+ else
+ {
+ use_bank(p_global->perso_img_bank);
+ perso_img_bank_data_ptr = bank_data_ptr;
+ }
+}
+void load_perso_cour()
+{
+ load_perso(p_global->perso_ptr);
+}
+void fin_perso()
+{
+ p_global->animationFlags &= 0x3F;
+ p_global->curPersoAnimPtr = 0;
+ p_global->ff_CA = 0;
+ p_global->perso_img_bank = -1;
+ anim_perfin();
+}
+void no_perso()
+{
+ if(p_global->displayFlags == DisplayFlags::dfPerson)
+ {
+ p_global->displayFlags = p_global->oldDisplayFlags;
+ fin_perso();
+ }
+ endpersovox();
+}
+void close_perso()
+{
+ char old;
+ endpersovox();
+ if (p_global->displayFlags == DisplayFlags::dfPerson && p_global->perso_ptr->id != PersonId::pidNarrator && p_global->eventType != EventType::etEventE)
+ {
+ rundcurs();
+ savedUnderSubtitles = 1;
+ restaurefondbulle();
+ afficher();
+ p_global->ff_103 = 16;
+ }
+ if(p_global->perso_ptr->id == PersonId::pidNarrator)
+ p_global->ff_103 = 69;
+ p_global->eloiHaveNews &= 1;
+ p_global->ff_CA = 0;
+ p_global->ff_F6 = 0;
+ if (p_global->displayFlags == DisplayFlags::dfPerson)
+ {
+ p_global->displayFlags = p_global->oldDisplayFlags;
+ p_global->animationFlags &= 0x3F;
+ p_global->curPersoAnimPtr = 0;
+ anim_perfin();
+ if(p_global->displayFlags & DisplayFlags::dfMirror)
+ {
+ gametomiroir(1);
+ scroll_pos = old_scroll_pos;
+ scroll();
+ return;
+ }
+ if(p_global->numGiveObjs)
+ {
+ if(!(p_global->displayFlags & DisplayFlags::dfFlag2))
+ showobjects();
+ p_global->numGiveObjs = 0;
+ }
+ if(p_global->ff_F2 & 1)
+ {
+ p_global->ff_102 = 6;
+ p_global->ff_F2 &= ~1;
+ }
+ old = p_global->newLocation;
+ p_global->newLocation = 0;
+ if(!(p_global->narratorSequence & 0x80))
+ p_global->ff_100 = -1;
+ maj_salle(p_global->roomNum);
+ p_global->newLocation = old;
+ }
+ if(p_global->chrono)
+ p_global->chrono_on = 1;
+}
+void af_fondsuiveur()
+{
+ char id = p_global->perso_ptr->id;
+ suiveur_t *suiveur = suiveurs_list;
+ for(;suiveur->id != -1;suiveur++)
+ {
+ if(suiveur->id == id)
+ {
+ int bank = 326;
+ if(suiveur->sx >= 320)
+ bank = 327;
+ use_bank(bank + p_global->roomBgBankNum);
+ noclipax_avecnoir(0, 0, 16);
+ break;
+ }
+ }
+}
+void af_fondperso1()
+{
+ unsigned char bank;
+ char *ptab;
+ if(p_global->perso_ptr == &kPersons[PER_MESSAGER])
+ {
+ gameIcons[0].sx = 0;
+ perso_rects[PER_MESSAGER].sx = 2;
+ bank = p_global->persoBackgroundBankIdx;
+ if(p_global->eventType == EventType::etEventE)
+ {
+ p_global->ff_103 = 1;
+ goto no_suiveur;
+ }
+ gameIcons[0].sx = 60;
+ perso_rects[PER_MESSAGER].sx = 62;
+ }
+ if(p_global->perso_ptr == &kPersons[PER_THOO])
+ {
+ bank = 37;
+ if(p_global->curObjectId == Objects::obShell)
+ goto no_suiveur;
+ }
+ ptab = kPersoRoomBankTable + p_global->perso_ptr->roomBankIdx;
+ bank = *ptab++;
+ if(!(p_global->perso_ptr->party & p_global->party))
+ {
+ while((bank = *ptab++) != 0xFF)
+ {
+ if(bank == (p_global->roomNum & 0xFF)) //TODO: signed vs unsigned - chg r31 to uns?
+ {
+ bank = *ptab;
+ break;
+ }
+ ptab++;
+ }
+ if(bank != 0xFF)
+ goto no_suiveur;
+ ptab = kPersoRoomBankTable + p_global->perso_ptr->roomBankIdx;
+ bank = *ptab++;
+ }
+ af_fondsuiveur();
+no_suiveur:;
+ if(!bank)
+ return;
+ use_bank(bank);
+ if(p_global->perso_ptr == &kPersons[PER_UNKN_156])
+ noclipax_avecnoir(0, 0, 16);
+ else
+ noclipax(0, 0, 16);
+}
+void af_fondperso()
+{
+ if(p_global->perso_ptr->bank)
+ {
+ fond_saved = 0;
+ af_fondperso1();
+ }
+}
+void setpersoicon()
+{
+ icon_t *icon = gameIcons, *icon2 = &gameIcons[28];
+ if(p_global->iconsIndex == 4)
+ return;
+ if(p_global->perso_ptr == &kPersons[PER_MESSAGER] && p_global->eventType == EventType::etEventE)
+ {
+ p_global->iconsIndex = 123;
+ return;
+ }
+ *icon2++ = *icon++; //TODO: is this ok?
+ *icon2++ = *icon++;
+ icon2->sx = -1;
+}
+void show_perso()
+{
+ perso_t *perso = p_global->perso_ptr;
+ if(perso->bank)
+ {
+ closesalle();
+ if(p_global->displayFlags != DisplayFlags::dfPerson)
+ {
+ if(p_global->displayFlags & DisplayFlags::dfMirror)
+ resetscroll();
+ p_global->oldDisplayFlags = p_global->displayFlags;
+ p_global->displayFlags = DisplayFlags::dfPerson;
+ load_perso(perso);
+ setpersoicon();
+ af_fondperso();
+ if(perso == &kPersons[PER_THOO] && p_global->curObjectId == Objects::obShell)
+ {
+ af_subtitle();
+ update_cursor();
+ needPaletteUpdate = 1;
+ afficher();
+ rundcurs();
+ return;
+ }
+ }
+ load_perso_cour();
+ addanim();
+ if(!p_global->curPersoAnimPtr)
+ {
+ af_perso();
+ af_subtitle();
+ }
+ restartAnimation = 1;
+ anim_perso();
+ if(perso != &kPersons[PER_UNKN_156])
+ update_cursor();
+ needPaletteUpdate = 1;
+ if(perso != &kPersons[PER_UNKN_156])
+ rundcurs();
+ afficher();
+ }
+ else
+ {
+ aflieu();
+ af_subtitle();
+ }
+}
+void showpersopanel()
+{
+ perso_t *perso = p_global->perso_ptr;
+ load_perso_cour();
+ addanim();
+ if(!p_global->curPersoAnimPtr)
+ {
+ af_perso();
+ af_subtitle();
+ }
+ restartAnimation = 1;
+ needPaletteUpdate = 1;
+ if(p_global->drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ anim_perso();
+ if(perso != &kPersons[PER_UNKN_156])
+ update_cursor();
+ afficher();
+ if(perso != &kPersons[PER_UNKN_156])
+ rundcurs();
+ p_global->drawFlags |= DrawFlags::drDrawFlag8;
+ p_global->iconsIndex = 112;
+}
+void getdatasync()
+{
+ short num = p_global->textNum;
+ if(p_global->textBankIndex != 1)
+ num += 565;
+ if(p_global->textBankIndex == 3)
+ num += 707;
+ if(num == 144)
+ num = 142;
+ animateTalking = ReadDataSync(num - 1);
+ if(animateTalking)
+ num_anim_frames = ReadNombreFrames();
+ else
+ num_anim_frames = 0;
+ if(p_global->textNum == 144)
+ num_anim_frames = 48;
+ animationTable = 0;
+}
+short ReadNombreFrames()
+{
+ short num = 0;
+ animationTable = gameLipsync + 7262; //TODO: fix me
+ while(*animationTable++ != 0xFF)
+ num++;
+ return num;
+}
+void waitendspeak()
+{
+ for(;;)
+ {
+ if(animationActive)
+ anim_perso();
+ musicspy();
+ afficher();
+ CLKeyboard_Read();
+ testPommeQ();
+ if(pomme_q)
+ {
+ close_perso();
+ PommeQ();
+ break;
+ }
+ if(!mouse_held)
+ if(CLMouse_IsDown())
+ break;
+ if(mouse_held)
+ if(!CLMouse_IsDown())
+ mouse_held = 0;
+ }
+ mouse_held = 1;
+}
+void my_bulle()
+{
+ unsigned char c;
+ unsigned char i;
+ short words_on_line, word_width, line_width;
+ unsigned char *icons = phraseIconsBuffer;
+ unsigned char *lines = phraseCoordsBuffer;
+ unsigned char *phrasePtr = phraseBuffer;
+ if(!p_global->textNum)
+ return;
+ p_global->numGiveObjs = 0;
+ p_global->giveobj1 = 0;
+ p_global->giveobj2 = 0;
+ p_global->giveobj3 = 0;
+ p_global->textWidthLimit = subtitles_x_width;
+ text_ptr = gettxtad(p_global->textNum);
+ num_text_lines = 0;
+ words_on_line = 0;
+ word_width = 0;
+ line_width = 0;
+ while((c = *text_ptr++) != 0xFF)
+ {
+ if(c == 0x11 || c == 0x13)
+ {
+ if(p_global->phaseNum <= 272 || p_global->phaseNum == 386)
+ {
+ p_global->eloiHaveNews = c & 0xF;
+ p_global->ff_4D = p_global->worldTyrannSighted;
+ }
+ }
+ else if(c >= 0x80 && c < 0x90)
+ SysBeep(1);
+ else if(c >= 0x90 && c < 0xA0)
+ {
+ while(*text_ptr++ != 0xFF) ;
+ text_ptr--;
+ }
+ else if(c >= 0xA0 && c < 0xC0)
+ p_global->textToken1 = c & 0xF;
+ else if(c >= 0xC0 && c < 0xD0)
+ p_global->textToken2 = c & 0xF;
+ else if(c >= 0xD0 && c < 0xE0)
+ {
+ unsigned char c1 = *text_ptr++;
+ if(c == 0xD2)
+#ifdef FAKE_DOS_VERSION
+ p_global->textWidthLimit = c1 + 160;
+#else
+ p_global->textWidthLimit = c1 + subtitles_x_center; //TODO: signed? 160 in pc ver
+#endif
+ else
+ {
+ unsigned char c2 = *text_ptr++;
+ switch(p_global->numGiveObjs)
+ {
+ case 0: p_global->giveobj1 = c2; break;
+ case 1: p_global->giveobj2 = c2; break;
+ case 2: p_global->giveobj3 = c2; break;
+ }
+ p_global->numGiveObjs++;
+ *icons++ = *text_ptr++;
+ *icons++ = *text_ptr++;
+ *icons++ = c2;
+ }
+ }
+ else if(c >= 0xE0 && c < 0xFF)
+ SysBeep(1);
+ else if(c != '\r')
+ {
+ unsigned char width;
+ short overrun;
+ *phrasePtr++ = c;
+ width = gameFont[c];
+#ifdef FAKE_DOS_VERSION
+ if (c == ' ')
+ width = space_width;
+#endif
+ word_width += width;
+ line_width += width;
+ overrun = line_width - p_global->textWidthLimit;
+ if(overrun > 0)
+ {
+ num_text_lines++;
+ if(c != ' ')
+ {
+ *lines++ = words_on_line;
+ *lines++ = word_width + space_width - overrun;
+ line_width = word_width;
+ }
+ else
+ {
+ *lines++ = words_on_line + 1;
+ *lines++ = space_width - overrun; //TODO: checkme
+ line_width = 0;
+ }
+ word_width = 0;
+ words_on_line = 0;
+ }
+ else
+ {
+ if(c == ' ')
+ {
+ words_on_line++;
+ word_width = 0;
+ }
+ }
+ }
+ }
+ num_text_lines++;
+ *lines++ = words_on_line + 1;
+ *lines++ = word_width;
+ *phrasePtr = c;
+ if(p_global->textBankIndex == 2 && p_global->textNum == 101 && p_global->pref_language == 1)
+ patchphrase();
+ my_pr_bulle();
+ if(!p_global->numGiveObjs)
+ return;
+ use_main_bank();
+ if(num_text_lines < 3)
+ num_text_lines = 3;
+ icons = phraseIconsBuffer;
+ for(i = 0;i < p_global->numGiveObjs;i++)
+ {
+ unsigned char x = *icons++;
+ unsigned char y = *icons++;
+ unsigned char s = *icons++;
+ spritesurbulle(52, x + subtitles_x_center, y - 1);
+ spritesurbulle(s + 9, x + subtitles_x_center + 1, y);
+ }
+}
+void my_pr_bulle()
+{
+ unsigned char *cur_out;
+ unsigned char *coo = phraseCoordsBuffer;
+ short extra_spacing, lines;
+ char done = 0;
+ CLBlitter_FillView(p_subtitlesview, 0);
+ if(p_global->pref_language == 0)
+ return;
+ textout = p_subtitlesview_buf;
+ text_ptr = phraseBuffer;
+ lines = 1;
+ while(!done)
+ {
+ unsigned char c;
+ short num_words = *coo++; // num words on line
+ short pad_size = *coo++; // amount of extra spacing
+ cur_out = textout;
+ extra_spacing = num_words > 1 ? pad_size / (num_words - 1) + 1 : 0;
+ if(lines == num_text_lines)
+ extra_spacing = 0;
+ c = *text_ptr++;
+ while(!done & (num_words > 0)) //TODO: bug - missed & ?
+ {
+ if(c < 0x80 && c != '\r')
+ {
+ if(c == ' ')
+ {
+ num_words--;
+ if (pad_size >= extra_spacing)
+ {
+ textout += extra_spacing + space_width;
+ pad_size -= extra_spacing;
+ }
+ else
+ {
+ textout += pad_size + space_width;
+ pad_size = 0;
+ }
+ }
+ else
+ {
+ short char_width = gameFont[c];
+ if(!(p_global->drawFlags & DrawFlags::drDrawMenu))
+ {
+ textout += subtitles_x_width;
+ if(!specialTextMode)
+ charsurbulle(c, 195, char_width);
+ textout++;
+ if(!specialTextMode)
+ charsurbulle(c, 195, char_width);
+ textout -= subtitles_x_width + 1;
+ }
+ if(specialTextMode)
+ charsurbulle(c, 250, char_width);
+ else
+ charsurbulle(c, 230, char_width);
+ textout += char_width;
+ }
+ }
+ else
+ monbreak();
+ c = *text_ptr++;
+ if(c == 0xFF)
+ done = 1;
+ }
+ textout = cur_out + subtitles_x_width * FONT_HEIGHT;
+ lines++;
+ text_ptr--;
+ }
+}
+void charsurbulle(unsigned char c, unsigned char color, short width)
+{
+ short w, h;
+ unsigned char *glyph = gameFont + 256 + c * FONT_HEIGHT;
+ textoutptr = textout;
+ for(h = 0;h < FONT_HEIGHT;h++)
+ {
+ unsigned char bits = *glyph++;
+ short mask = 0x80;
+ for(w = 0;w < width;w++)
+ {
+ if(bits & mask)
+ *textoutptr = color;
+ textoutptr++;
+ mask >>= 1;
+ }
+ textoutptr += subtitles_x_width - width;
+ }
+}
+void af_subtitle()
+{
+ short w, h, y;
+ unsigned char *src = p_subtitlesview_buf, *dst = p_mainview_buf;
+ if(p_global->displayFlags & DisplayFlags::dfFlag2)
+ {
+ y = 174;
+ if((p_global->drawFlags & DrawFlags::drDrawMenu) && num_text_lines == 1)
+ y = 167;
+ dst += 640 * (y - num_text_lines * FONT_HEIGHT) + subtitles_x_scr_margin;
+ }
+ else
+ {
+ y = 174;
+ dst += 640 * (y - num_text_lines * FONT_HEIGHT) + scroll_pos + subtitles_x_scr_margin;
+ }
+ if(animationActive && !personTalking)
+ return;
+ sauvefondbulle(y);
+ for(h = 0;h < num_text_lines * FONT_HEIGHT + 1;h++)
+ {
+ for(w = 0;w < subtitles_x_width;w++)
+ {
+ unsigned char c = *src++;
+ if(c)
+ *dst = c;
+ dst++;
+ }
+ dst += 640 - subtitles_x_width;
+ }
+}
+void sauvefondbulle(short y)
+{
+ underSubtitlesScreenRect.sy = y - num_text_lines * FONT_HEIGHT;
+ underSubtitlesScreenRect.sx = scroll_pos + subtitles_x_scr_margin;
+ underSubtitlesScreenRect.ex = scroll_pos + subtitles_x_scr_margin + subtitles_x_width - 1;
+ underSubtitlesScreenRect.ey = y;
+ underSubtitlesBackupRect.sy = 0;
+ underSubtitlesBackupRect.ey = num_text_lines * FONT_HEIGHT;
+ CLBlitter_CopyViewRect(p_mainview, p_underSubtitlesView, &underSubtitlesScreenRect, &underSubtitlesBackupRect);
+ savedUnderSubtitles = 1;
+}
+void restaurefondbulle()
+{
+ if(!savedUnderSubtitles)
+ return;
+ CLBlitter_CopyViewRect(p_underSubtitlesView, p_mainview, &underSubtitlesBackupRect, &underSubtitlesScreenRect);
+ savedUnderSubtitles = 0;
+}
+void af_subtitlehnm()
+{
+ short x, y;
+ unsigned char *src = p_subtitlesview_buf;
+ unsigned char *dst = p_hnmview_buf + subtitles_x_scr_margin + (158 - num_text_lines * FONT_HEIGHT) * 320;
+ for(y = 0;y < num_text_lines * FONT_HEIGHT;y++)
+ {
+ for(x = 0;x < subtitles_x_width;x++)
+ {
+ char c = *src++;
+ if(c)
+ *dst = c;
+ dst++;
+ }
+ dst += 320 - subtitles_x_width;
+ }
+}
+void patchphrase()
+{
+ phraseBuffer[36] = 'c';
+}
+void vavapers()
+{
+ perso_t *perso = p_global->perso_ptr;
+ p_global->curPersoFlags = perso->flags;
+ p_global->curPersoItems = perso->items;
+ p_global->curPersoPowers = perso->powers;
+}
+void citadelle()
+{
+ p_global->ff_69++;
+ p_global->ff_F6++;
+ byte_30AFE = 1;
+ byte_30B00 = 1;
+}
+void choixzone()
+{
+ if(p_global->giveobj3)
+ p_global->iconsIndex = 6;
+ else
+ p_global->iconsIndex = 10;
+ p_global->autoDialog = 0;
+ putobject();
+}
+void showevents1()
+{
+ p_global->ff_113 = 0;
+ perso_ici(3);
+}
+void showevents()
+{
+ if(p_global->eventType && p_global->displayFlags != DisplayFlags::dfPerson)
+ showevents1();
+}
+void parle_mfin()
+{
+ char curobj;
+ object_t *obj;
+ perso_t *perso = p_global->perso_ptr;
+ if(p_global->curObjectId)
+ {
+ curobj = p_global->curObjectId;
+ if(p_global->dialogType == DialogType::dtHint)
+ return;
+ obj = getobjaddr(p_global->curObjectId);
+ if(p_global->dialogType == DialogType::dtDinoItem)
+ perso = p_global->room_perso;
+ if(verif_oui())
+ {
+ loseobject(p_global->curObjectId);
+ perso->powers |= obj->powerMask;
+ }
+ perso->items |= obj->itemMask;
+ SpecialObjets(perso, curobj);
+ return;
+ }
+ if(!verif_oui())
+ return;
+ nextinfo();
+ if(!p_global->last_info)
+ byte_30B00 = 1;
+ else
+ {
+ p_global->next_dialog_ptr = 0;
+ byte_30B00 = 0;
+ }
+}
+void parlemoi_normal()
+{
+ char ok;
+ dial_t *dial;
+ if(!p_global->next_dialog_ptr)
+ {
+ perso_t *perso = p_global->perso_ptr;
+ if(perso)
+ {
+ short num = (perso->id << 3) | p_global->dialogType;
+ dial = (dial_t*)GetElem(gameDialogs, num);
+ }
+ else
+ {
+ close_perso();
+ return;
+ }
+ }
+ else
+ {
+ if(byte_30B00)
+ {
+ close_perso();
+ return;
+ }
+ dial = p_global->next_dialog_ptr;
+ }
+ ok = dial_scan(dial);
+ p_global->next_dialog_ptr = p_global->dialog_ptr;
+ byte_30B00 = 0;
+ if(!ok)
+ close_perso();
+ else
+ parle_mfin();
+}
+void parle_moi()
+{
+ unsigned char r28;
+ char ok;
+ dial_t *dial;
+ endpersovox();
+ r28 = p_global->ff_F6;
+ p_global->ff_F6 = 0;
+ if(!r28)
+ {
+ init_non();
+ if(p_global->drawFlags & DrawFlags::drDrawInventory)
+ showobjects();
+ if(p_global->drawFlags & DrawFlags::drDrawTopScreen)
+ afftopscr();
+ if(p_global->curObjectId)
+ {
+ if(p_global->dialogType == DialogType::dtTalk)
+ {
+ p_global->dialogType = DialogType::dtItem;
+ p_global->next_dialog_ptr = 0;
+ byte_30B00 = 0;
+ }
+ parlemoi_normal();
+ return;
+ }
+ if(p_global->dialogType == DialogType::dtItem)
+ {
+ p_global->dialogType = DialogType::dtTalk;
+ if(!byte_30B00)
+ p_global->next_dialog_ptr = 0;
+ }
+ if(byte_30AFE)
+ {
+ parlemoi_normal();
+ return;
+ }
+ if(!p_global->last_dialog_ptr)
+ {
+ short num = 160;
+ if(p_global->phaseNum >= 400)
+ num++;
+ dial = (dial_t*)GetElem(gameDialogs, num);
+ }
+ else
+ dial = p_global->last_dialog_ptr;
+ ok = dial_scan(dial);
+ p_global->last_dialog_ptr = p_global->dialog_ptr;
+ byte_30AFE = 0;
+ if(!ok)
+ {
+ byte_30AFE = 1;
+ if(p_global->ff_60)
+ {
+ if(p_global->perso_ptr == &kPersons[PER_MESSAGER])
+ {
+ p_global->dialogType = 0;
+ if(p_global->eloiHaveNews)
+ parlemoi_normal();
+ else
+ close_perso();
+ }
+ else
+ close_perso();
+ }
+ else
+ parlemoi_normal();
+ }
+ else
+ parle_mfin();
+ }
+ else
+ close_perso();
+}
+void init_perso_ptr(perso_t *perso)
+{
+ p_global->metPersonsMask1 |= perso->party;
+ p_global->metPersonsMask2 |= perso->party;
+ p_global->next_dialog_ptr = 0;
+ byte_30B00 = 0;
+ dialogSkipFlags = DialogFlags::dfSpoken;
+ p_global->ff_60 = 0;
+ p_global->textToken1 = 0;
+}
+void perso1(perso_t *perso)
+{
+ p_global->phaseActionsCount++;
+ if(perso == &kPersons[PER_THOO])
+ p_global->phaseActionsCount--;
+ p_global->perso_ptr = perso;
+ init_perso_ptr(perso);
+ parle_moi();
+}
+void perso_normal(perso_t *perso)
+{
+ p_global->last_dialog_ptr = 0;
+ p_global->dialogType = 0;
+ byte_30AFE = 0;
+ perso1(perso);
+}
+void persoparle(short pers)
+{
+ char res;
+ unsigned short idx;
+ unsigned char *ptr;
+ perso_t *perso = &kPersons[pers];
+ p_global->perso_ptr = perso;
+ p_global->dialogType = DialogType::dtInspect;
+ idx = perso->id * 8 | p_global->dialogType;
+ res = dialoscansvmas((dial_t*)GetElem(gameDialogs, idx));
+ aflieu();
+ af_subtitle();
+ persovox();
+ p_global->ff_CA = 0;
+ p_global->dialogType = 0;
+}
+void roi() { perso_normal(&kPersons[PER_ROI]); }
+void dina() { perso_normal(&kPersons[PER_DINA]); }
+void thoo() { perso_normal(&kPersons[PER_THOO]); }
+void monk() { perso_normal(&kPersons[PER_MONK]); }
+void bourreau() { perso_normal(&kPersons[PER_BOURREAU]); }
+void messager() { perso_normal(&kPersons[PER_MESSAGER]); }
+void mango() { perso_normal(&kPersons[PER_MANGO]); }
+void eve() { perso_normal(&kPersons[PER_EVE]); }
+void azia() { perso_normal(&kPersons[PER_AZIA]); }
+void mammi()
+{
+ perso_t *perso;
+ for(perso = &kPersons[PER_MAMMI];perso->party == PersonMask::pmLeader;perso++)
+ {
+ if(perso->roomNum == p_global->roomNum)
+ {
+ perso_normal(perso);
+ break;
+ }
+ }
+}
+void gardes() { perso_normal(&kPersons[PER_GARDES]); }
+void bambou() { perso_normal(&kPersons[PER_BAMBOO]); }
+void kabuka() { if(p_global->roomNum == 0x711) perso_normal(&kPersons[PER_KABUKA]); else bambou(); }
+void fisher() { if(p_global->roomNum == 0x902) perso_normal(&kPersons[PER_FISHER]); else kabuka(); }
+void dino()
+{
+ perso_t *perso = p_global->room_perso;
+ if(!perso)
+ return;
+ byte_30AFE = 1;
+ p_global->dialogType = 0;
+ p_global->roomPersoFlags = perso->flags;
+ p_global->roomPersoItems = perso->items;
+ p_global->roomPersoPowers = perso->powers;
+ p_global->perso_ptr = perso;
+ init_perso_ptr(perso);
+ debug("beg dino talk");
+ parle_moi();
+ debug("end dino talk");
+ if (p_global->areaNum == Areas::arWhiteArch)
+ return;
+ if(p_global->ff_60)
+ waitendspeak();
+ if(pomme_q)
+ return;
+ perso = &kPersons[PER_MANGO];
+ if(!(p_global->party & PersonMask::pmMungo))
+ {
+ perso = &kPersons[PER_DINA];
+ if(!(p_global->party & PersonMask::pmDina))
+ {
+ perso = &kPersons[PER_EVE];
+ if(!(p_global->party & PersonMask::pmEve))
+ {
+ perso = &kPersons[PER_GARDES];
+ }
+ }
+ }
+ p_global->dialogType = DialogType::dtDinoAction;
+ if(p_global->curObjectId)
+ p_global->dialogType = DialogType::dtDinoItem;
+ perso1(perso);
+ if(p_global->roomPersoType == PersonFlags::pftMosasaurus && !p_global->curObjectId)
+ {
+ p_global->area_ptr->flags |= AreaFlags::afFlag20;
+ lieuvava(p_global->area_ptr);
+ }
+}
+void tyran()
+{
+ perso_t *perso = p_global->room_perso;
+ if(!perso)
+ return;
+ byte_30AFE = 1;
+ p_global->dialogType = 0;
+ p_global->roomPersoFlags = perso->flags;
+ p_global->perso_ptr = perso;
+ init_perso_ptr(perso);
+ perso = &kPersons[PER_MANGO];
+ if(!(p_global->party & PersonMask::pmMungo))
+ {
+ perso = &kPersons[PER_DINA];
+ if(!(p_global->party & PersonMask::pmDina))
+ {
+ perso = &kPersons[PER_EVE];
+ if(!(p_global->party & PersonMask::pmEve))
+ {
+ perso = &kPersons[PER_GARDES];
+ }
+ }
+ }
+ p_global->dialogType = DialogType::dtDinoAction;
+ if(p_global->curObjectId)
+ p_global->dialogType = DialogType::dtDinoItem;
+ perso1(perso);
+}
+void morkus() { perso_normal(&kPersons[PER_MORKUS]); }
+void comment()
+{
+ perso_t *perso;
+ perso = &kPersons[PER_DINA];
+ if(!(p_global->party & PersonMask::pmDina))
+ {
+ perso = &kPersons[PER_EVE];
+ if(!(p_global->party & PersonMask::pmEve))
+ {
+ perso = &kPersons[PER_GARDES];
+ if(!(p_global->party & PersonMask::pmThugg))
+ {
+ return;
+ }
+ }
+ }
+ p_global->dialogType = DialogType::dtHint;
+ perso1(perso);
+}
+void adam()
+{
+ char *objvid;
+ object_t *object;
+ short vid;
+ resetscroll();
+ switch(p_global->curObjectId)
+ {
+ case Objects::obNone:
+ gotopanel();
+ break;
+ case Objects::obRoot:
+ if (p_global->roomNum == 2817
+ && p_global->phaseNum > 496 && p_global->phaseNum < 512)
+ {
+ bigphase1();
+ loseobject(Objects::obRoot);
+ p_global->ff_100 = -1;
+ quitmiroir();
+ maj_salle(p_global->roomNum);
+ reste_ici(5);
+ p_global->eventType = EventType::etEvent3;
+ showevents();
+ waitendspeak();
+ if(pomme_q)
+ return;
+ close_perso();
+ reste_ici(5);
+ p_global->roomNum = 2818;
+ p_global->areaNum = Areas::arWhiteArch;
+ p_global->eventType = EventType::etEvent5;
+ p_global->valleyVidNum = 0;
+ p_global->ff_102 = 6;
+ p_global->newMusicType = MusicType::mtNormal;
+ maj_salle(p_global->roomNum);
+ }
+ else
+ {
+ p_global->dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_EVE]);
+ }
+ break;
+ case Objects::obShell:
+ p_global->dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_THOO]);
+ break;
+ case Objects::obFlute:
+ case Objects::obTrumpet:
+ if(p_global->roomPersoType)
+ {
+ quitmiroir();
+ maj_salle(p_global->roomNum);
+ dino();
+ }
+ else
+ comment();
+ break;
+ case Objects::obTablet1:
+ case Objects::obTablet2:
+ case Objects::obTablet3:
+ case Objects::obTablet4:
+ case Objects::obTablet5:
+ case Objects::obTablet6:
+ if((p_global->partyOutside & PersonMask::pmDina)
+ && p_global->curObjectId == Objects::obTablet1 && p_global->phaseNum == 370)
+ incphase1();
+ objvid = &kTabletView[(p_global->curObjectId - Objects::obTablet1) * 2];
+ object = getobjaddr(*objvid++);
+ vid = 84;
+ if(!object->count)
+ vid = *objvid;
+ bars_out();
+ specialTextMode = 1;
+ playhnm(vid);
+ needPaletteUpdate = 1;
+ p_global->ff_102 = 16;
+ bars_in();
+ gametomiroir(0);
+ break;
+ case Objects::obApple:
+ case Objects::obShroom:
+ case Objects::obBadShroom:
+ case Objects::obNest:
+ case Objects::obFullNest:
+ case Objects::obDrum:
+ if(p_global->party & PersonMask::pmThugg)
+ {
+ p_global->dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_GARDES]);
+ }
+ break;
+ default:
+ comment();
+ }
+}
+void init_oui() { word_30AFC = -1; }
+void init_non() { word_30AFC = 0; }
+void oui() { word_30AFC = -1; }
+void non() { word_30AFC = 0; }
+char verif_oui(){ return word_30AFC == -1; }
+void SpcChampi(perso_t *perso)
+{
+ perso->flags |= PersonFlags::pf10;
+ p_global->area_ptr->flags |= AreaFlags::afFlag2;
+ p_global->curAreaFlags |= AreaFlags::afFlag2;
+}
+void SpcNidv(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ perso->flags |= PersonFlags::pf10;
+ p_global->roomPersoFlags |= PersonFlags::pf10;
+ p_global->gameFlags |= GameFlags::gfFlag400;
+ if(p_global->perso_ptr == &kPersons[PER_EVE])
+ {
+ p_global->area_ptr->flags |= AreaFlags::afFlag4;
+ p_global->curAreaFlags |= AreaFlags::afFlag4;
+ perso->flags |= PersonFlags::pfInParty;
+ p_global->roomPersoFlags |= PersonFlags::pfInParty;
+ lieuvava(p_global->area_ptr);
+ }
+ else
+ {
+ perso->flags &= ~PersonFlags::pf10;
+ p_global->roomPersoFlags &= ~PersonFlags::pf10;
+ }
+}
+void SpcNido(perso_t *perso)
+{
+ if(perso == &kPersons[PER_GARDES])
+ giveobject();
+}
+void SpcPomme(perso_t *perso)
+{
+ perso->flags |= PersonFlags::pf10;
+ p_global->area_ptr->flags |= AreaFlags::afFlag8;
+ p_global->curAreaFlags |= AreaFlags::afFlag8;
+ p_global->gameFlags |= GameFlags::gfFlag200;
+}
+void SpcOr(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ perso->items = currentSpecialObject->itemMask;
+ p_global->roomPersoItems = currentSpecialObject->itemMask;
+ perso->flags |= PersonFlags::pf10;
+ perso->flags &= ~PersonFlags::pfInParty;
+ perso->targetLoc = 0;
+ p_global->area_ptr->flags |= AreaFlags::afGaveGold;
+ p_global->curAreaFlags |= AreaFlags::afGaveGold;
+ if(p_global->phaseNum == 226)
+ incphase1();
+}
+void SpcPrisme(perso_t *perso)
+{
+ if(perso == &kPersons[PER_DINA])
+ {
+ if(p_global->partyOutside & PersonMask::pmMonk)
+ p_global->gameFlags |= GameFlags::gfPrismAndMonk;
+ }
+}
+void SpcTalisman(perso_t *perso)
+{
+ if(perso == &kPersons[PER_DINA])
+ suis_moi(1);
+}
+void SpcMasque(perso_t *perso)
+{
+ if(perso == &kPersons[PER_BAMBOO])
+ {
+ dialautoon();
+ byte_30AFE = 1;
+ }
+}
+void SpcSac(perso_t *perso)
+{
+ if(p_global->textToken1 != 3)
+ return;
+ if(perso == &kPersons[PER_KABUKA] || perso == &kPersons[PER_MAMMI_3])
+ loseobject(currentSpecialObject->id);
+}
+void SpcTrompet(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ p_global->ff_54 = 4;
+ winobject(Objects::obTrumpet);
+ p_global->drawFlags |= DrawFlags::drDrawInventory;
+ byte_30B00 = 1;
+ TyranMeurt(p_global->room_perso);
+}
+void SpcArmes(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ perso->powers = currentSpecialObject->powerMask;
+ p_global->roomPersoPowers = currentSpecialObject->powerMask;
+ giveobject();
+}
+void SpcInstru(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ if(perso == &kPersons[PER_MONK])
+ {
+ p_global->partyInstruments &= ~1; //TODO: check me
+ if(currentSpecialObject->id == Objects::obRing)
+ {
+ p_global->partyInstruments |= 1;
+ p_global->monkGotRing++; //TODO: |= 1 ?
+ }
+ }
+ if(perso == &kPersons[PER_GARDES])
+ {
+ p_global->partyInstruments &= ~2;
+ if(currentSpecialObject->id == Objects::obDrum)
+ p_global->partyInstruments |= 2;
+ }
+ perso->powers = currentSpecialObject->powerMask;
+ p_global->curPersoPowers = currentSpecialObject->powerMask;
+ giveobject();
+}
+void SpcOeuf(perso_t *perso)
+{
+ if(!verif_oui())
+ return;
+ gameIcons[131].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 62;
+ dialautoon();
+}
+void TyranMeurt(perso_t *perso)
+{
+ perso->flags |= PersonFlags::pf80;
+ perso->roomNum = 0;
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannIn);
+ p_global->roomPersoType = 0;
+ p_global->roomPersoFlags = 0;
+ p_global->chrono_on = 0;
+}
+void SpecialObjets(perso_t *perso, char objid)
+{
+ typedef void (EdenGameImpl::*disp_t)(perso_t *perso);
+ struct spcobj_t {
+ char persoType;
+ char objectId;
+// void (EdenGameImpl::*disp)(perso_t *perso);
+ disp_t disp;
+ };
+
+ static spcobj_t kSpecialObjectActions[] = {
+ // perso, obj, disp
+ { PersonFlags::pfType8, Objects::obShroom, &EdenGameImpl::SpcChampi },
+ { PersonFlags::pftTriceraptor, Objects::obNest, &EdenGameImpl::SpcNidv },
+ { PersonFlags::pfType0, Objects::obFullNest, &EdenGameImpl::SpcNido },
+ { PersonFlags::pftMosasaurus, Objects::obApple, &EdenGameImpl::SpcPomme },
+ { PersonFlags::pftVelociraptor, Objects::obGold, &EdenGameImpl::SpcOr },
+ { PersonFlags::pfType0, Objects::obPrism, &EdenGameImpl::SpcPrisme },
+ { PersonFlags::pfType0, Objects::obTalisman, &EdenGameImpl::SpcTalisman },
+ { PersonFlags::pfType2, Objects::obMaskOfDeath, &EdenGameImpl::SpcMasque },
+ { PersonFlags::pfType2, Objects::obMaskOfBonding, &EdenGameImpl::SpcMasque },
+ { PersonFlags::pfType2, Objects::obMaskOfBirth, &EdenGameImpl::SpcMasque },
+ { PersonFlags::pfType0, Objects::obBag, &EdenGameImpl::SpcSac },
+ { PersonFlags::pfType2, Objects::obBag, &EdenGameImpl::SpcSac },
+ { PersonFlags::pftTyrann, Objects::obTrumpet, &EdenGameImpl::SpcTrompet },
+ { PersonFlags::pftVelociraptor, Objects::obEyeInTheStorm, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pftVelociraptor, Objects::obSkyHammer, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pftVelociraptor, Objects::obFireInTheClouds, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pftVelociraptor, Objects::obWithinAndWithout, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pftVelociraptor, Objects::obEyeInTheCyclone, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pftVelociraptor, Objects::obRiverThatWinds, &EdenGameImpl::SpcArmes },
+ { PersonFlags::pfType0, Objects::obTrumpet, &EdenGameImpl::SpcInstru },
+ { PersonFlags::pfType0, Objects::obDrum, &EdenGameImpl::SpcInstru },
+ { PersonFlags::pfType0, Objects::obRing, &EdenGameImpl::SpcInstru },
+ { PersonFlags::pfType0, Objects::obEgg, &EdenGameImpl::SpcOeuf },
+ { -1, -1, nullptr }
+ };
+ spcobj_t *spcobj = kSpecialObjectActions;
+ char persoType = perso->flags & PersonFlags::pfTypeMask;
+ currentSpecialObject = &objects[objid - 1];
+ for (; spcobj->persoType != -1; spcobj++)
+ {
+ if (spcobj->objectId == objid && spcobj->persoType == persoType)
+ {
+ (this->*spcobj->disp)(perso);
+ break;
+ }
+ }
+}
+
+void dialautoon()
+{
+ p_global->iconsIndex = 4;
+ p_global->autoDialog = -1;
+ putobject();
+}
+void dialautooff()
+{
+ p_global->iconsIndex = 0x10;
+ p_global->autoDialog = 0;
+}
+void follow()
+{
+ if(p_global->roomPersoType == PersonFlags::pfType12)
+ {
+ debug("follow: hiding person %d", p_global->room_perso - kPersons);
+ p_global->room_perso->flags |= PersonFlags::pf80;
+ p_global->room_perso->roomNum = 0;
+ p_global->gameFlags |= GameFlags::gfFlag8;
+ gameIcons[123].object_id = 18;
+ gameIcons[124].object_id = 35;
+ gameIcons[125].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 56;
+ }
+ else
+ suis_moi5();
+}
+void dialonfollow()
+{
+ p_global->iconsIndex = 4;
+ p_global->autoDialog = -1;
+ follow();
+}
+void abortdial()
+{
+ p_global->ff_F6++;
+ if(p_global->roomPersoType != PersonFlags::pftTriceraptor || p_global->perso_ptr != &kPersons[PER_EVE])
+ return;
+ p_global->area_ptr->flags |= AreaFlags::afFlag4;
+ p_global->curAreaFlags |= AreaFlags::afFlag4;
+ p_global->room_perso->flags |= PersonFlags::pfInParty;
+ p_global->roomPersoFlags |= PersonFlags::pfInParty;
+ lieuvava(p_global->area_ptr);
+}
+void narrateur()
+{
+ if(!(p_global->displayFlags & DisplayFlags::dfFlag1))
+ return;
+ if(!p_global->narratorSequence)
+ {
+ if(p_global->ff_6A == p_global->ff_69)
+ goto skip;
+ buildcita();
+ }
+ p_global->ff_F5 |= 0x80;
+ p_global->ff_F2 &= ~1; //TODO: check me
+ p_global->perso_ptr = &kPersons[PER_UNKN_156];
+ p_global->ff_60 = 0;
+ p_global->eventType = 0;
+ p_global->ff_103 = 69;
+ if(dialo_even(&kPersons[PER_UNKN_156]))
+ {
+ p_global->narrator_dialog_ptr = p_global->dialog_ptr;
+ dialautoon();
+ p_global->ff_F2 |= 1;
+ waitendspeak();
+ if(pomme_q)
+ return;
+ endpersovox();
+ while(dialoscansvmas(p_global->narrator_dialog_ptr))
+ {
+ p_global->narrator_dialog_ptr = p_global->dialog_ptr;
+ waitendspeak();
+ if(pomme_q)
+ return;
+ endpersovox();
+ }
+ p_global->narrator_dialog_ptr = p_global->dialog_ptr;
+ p_global->ff_102 = 0;
+ p_global->ff_103 = 0;
+ close_perso();
+ lieuvava(p_global->area_ptr);
+ if(p_global->narratorSequence == 8)
+ deplaval(134);
+ }
+ p_global->ff_103 = 0;
+ if(p_global->narratorSequence == 10)
+ {
+ suis_moi(5);
+ suis_moi(7);
+ suis_moi(3);
+ suis_moi(18);
+ reste_ici(6);
+ p_global->eloiHaveNews = 0;
+ deplaval(139);
+ }
+ p_global->eventType = EventType::etEventD;
+ showevents();
+ p_global->ff_F5 &= ~0x80;
+skip:;
+ p_global->ff_F2 &= ~1; //TODO: check me
+ if(p_global->narratorSequence > 50 && p_global->narratorSequence <= 80)
+ p_global->endGameFlag = 50;
+ if(p_global->narratorSequence == 3)
+ chronoon(1200);
+ p_global->narratorSequence = 0;
+
+}
+void vrf_phrases_file()
+{
+ short num = 3;
+ if(p_global->dialog_ptr < (dial_t*)GetElem(gameDialogs, 48))
+ num = 1;
+ else if(p_global->dialog_ptr < (dial_t*)GetElem(gameDialogs, 128))
+ num = 2;
+ p_global->textBankIndex = num;
+ if(p_global->pref_language)
+ num += (p_global->pref_language - 1) * 3;
+ if(num == lastPhrasesFile)
+ return;
+ lastPhrasesFile = num;
+ num += 404;
+ loadfile(num, gamePhrases);
+ verifh(gamePhrases);
+}
+unsigned char* gettxtad(short id)
+{
+ vrf_phrases_file();
+ return (unsigned char*)GetElem(gamePhrases, id - 1);
+}
+void gotocarte()
+{
+ char newArea, curArea;
+ goto_t *go = &gotos[current_spot2->object_id];
+ endpersovox();
+ newArea = go->areaNum;
+ p_global->newRoomNum = (go->areaNum << 8) | 1;
+ p_global->newLocation = 1;
+ p_global->prevLocation = p_global->roomNum & 0xFF;
+ curArea = p_global->roomNum >> 8;
+ if(curArea == go->areaNum)
+ newArea = 0;
+ else
+ {
+ for(;go->curAreaNum != 0xFF;go++)
+ if(go->curAreaNum == curArea)
+ break;
+ if(go->areaNum == 0xFF)
+ return;
+ }
+ p_global->eventType = EventType::etGotoArea | newArea;
+ init_oui();
+ showevents1();
+ waitendspeak();
+ if(pomme_q)
+ return;
+ close_perso();
+ if(verif_oui())
+ gotolieu(go);
+}
+void record()
+{
+ short i;
+ tape_t *tape;
+ perso_t *perso;
+ if(p_global->curObjectId)
+ return;
+ if(p_global->perso_ptr >= &kPersons[PER_UNKN_18C])
+ return;
+ if(p_global->eventType == EventType::etEventE || p_global->eventType >= EventType::etGotoArea)
+ return;
+ for(tape = tapes;tape != tapes + MAX_TAPES;tape++)
+ if(tape->textNum == p_global->textNum)
+ return;
+ for(tape = tapes, i = 0;i < MAX_TAPES - 1;i++)
+ {
+ tape->textNum = tape[+1].textNum;
+ tape->perso = tape[+1].perso;
+ tape->party = tape[+1].party;
+ tape->roomNum = tape[+1].roomNum;
+ tape->bgBankNum = tape[+1].bgBankNum;
+ tape->dialog = tape[+1].dialog;
+ tape++;
+ }
+ perso = p_global->perso_ptr;
+ if(perso == &kPersons[PER_EVE])
+ perso = p_global->phaseNum >= 352 ? &kPersons[PER_UNKN_372]
+ : &kPersons[PER_UNKN_402];
+ tape->textNum = p_global->textNum;
+ tape->perso = perso;
+ tape->party = p_global->party;
+ tape->roomNum = p_global->roomNum;
+ tape->bgBankNum = p_global->roomBgBankNum;
+ tape->dialog = p_global->dialog_ptr;
+}
+char dial_scan(dial_t *dial)
+{
+ unsigned char flags;
+ unsigned char hidx, lidx;
+ char bidx, pnum;
+ short i;
+ unsigned short mask;
+ perso_t *perso;
+ if(p_global->numGiveObjs)
+ {
+ if(!(p_global->displayFlags & DisplayFlags::dfFlag2))
+ showobjects();
+ p_global->numGiveObjs = 0;
+ }
+ p_global->dialog_ptr = dial;
+ vavapers();
+ p_global->phraseBufferPtr = phraseBuffer;
+ for(;;p_global->dialog_ptr++)
+ {
+ for(;;p_global->dialog_ptr++)
+ {
+ if (p_global->dialog_ptr->flags == -1 && p_global->dialog_ptr->condNumLow == -1)
+ return 0;
+ flags = p_global->dialog_ptr->flags;
+ p_global->dialogFlags = flags;
+ if (!(flags & DialogFlags::dfSpoken) || (flags & DialogFlags::dfRepeatable))
+ {
+ hidx = (p_global->dialog_ptr->textCondHiMask >> 6) & 3;
+ lidx = p_global->dialog_ptr->condNumLow;
+ if(flags & 0x10)
+ hidx |= 4;
+ if(testcondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ }
+ else
+ {
+ if(flags & dialogSkipFlags)
+ continue;
+ hidx = (p_global->dialog_ptr->textCondHiMask >> 6) & 3;
+ lidx = p_global->dialog_ptr->condNumLow;
+ if(flags & 0x10)
+ hidx |= 4;
+ if(testcondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ }
+ }
+ bidx = (p_global->dialog_ptr->textCondHiMask >> 2) & 0xF;
+ if(!bidx)
+ goto no_perso; //TODO: rearrange
+ mask = (p_global->party | p_global->partyOutside) & (1 << (bidx - 1));
+ if(mask)
+ break;
+ }
+ for(perso = kPersons;!(perso->party == mask && perso->roomNum == p_global->roomNum);perso++) ; //Find matching
+ p_global->perso_ptr = perso;
+ init_perso_ptr(perso);
+ no_perso();
+no_perso:;
+ hidx = p_global->dialog_ptr->textCondHiMask;
+ lidx = p_global->dialog_ptr->textNumLow;
+ p_global->textNum = ((hidx << 8) | lidx) & 0x3FF;
+ if(p_global->phraseBufferPtr != phraseBuffer)
+ {
+ for(i = 0;i < 32;i++)
+ SysBeep(1);
+ }
+ else
+ my_bulle();
+ if(!dword_30B04)
+ {
+ static void (EdenGameImpl::*talk_subject[])() = {
+ &EdenGameImpl::oui,
+ &EdenGameImpl::non,
+ &EdenGameImpl::eloipart,
+ &EdenGameImpl::dialautoon,
+ &EdenGameImpl::dialautooff,
+ &EdenGameImpl::stay_here,
+ &EdenGameImpl::follow,
+ &EdenGameImpl::citadelle,
+ &EdenGameImpl::dialonfollow,
+ &EdenGameImpl::abortdial,
+ &EdenGameImpl::incphase,
+ &EdenGameImpl::bigphase,
+ &EdenGameImpl::giveobject,
+ &EdenGameImpl::choixzone,
+ &EdenGameImpl::lostobject
+ };
+ pnum = p_global->dialog_ptr->flags & 0xF;
+ if(pnum)
+ (this->*talk_subject[pnum - 1])();
+ p_global->ff_60 = -1;
+ p_global->dialog_ptr->flags |= DialogFlags::dfSpoken;
+ p_global->dialog_ptr++;
+ }
+ if(p_global->dialogType != DialogType::dtInspect)
+ {
+ record();
+ getdatasync();
+ show_perso();
+ persovox();
+ }
+ return 1;
+}
+char dialoscansvmas(dial_t *dial)
+{
+ char res;
+ char old = dialogSkipFlags;
+ dialogSkipFlags = DialogFlags::df20;
+ res = dial_scan(dial);
+ dialogSkipFlags = old;
+ return res;
+}
+char dialo_even(perso_t *perso)
+{
+ char res;
+ int num;
+ dial_t *dial;
+ p_global->perso_ptr = perso;
+ num = (perso->id << 3) | DialogType::dtEvent;
+ dial = (dial_t*)GetElem(gameDialogs, num);
+ res = dialoscansvmas(dial);
+ p_global->last_dialog_ptr = 0;
+ byte_30AFE = 0;
+ return res;
+}
+void stay_here()
+{
+ if(p_global->perso_ptr == &kPersons[PER_DINA] && p_global->roomNum == 260)
+ p_global->gameFlags |= GameFlags::gfFlag1000;
+ reste_ici5();
+}
+void mort(short vid)
+{
+ bars_out();
+ playhnm(vid);
+ fadetoblack(2);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(p_mainview, 0);
+ bars_in();
+ p_global->narratorSequence = 51;
+ p_global->newMusicType = MusicType::mtNormal;
+ musique();
+ musicspy();
+}
+void evenchrono()
+{
+ unsigned short old;
+ if(!(p_global->displayFlags & DisplayFlags::dfFlag1))
+ return;
+ old = p_global->gameTime;
+ currentTime = TimerTicks / 100;
+ p_global->gameTime = currentTime;
+ if(p_global->gameTime <= old)
+ return;
+ heurepasse();
+ if(!(p_global->chrono_on & 1))
+ return;
+ p_global->chrono -= 200;
+ if(p_global->chrono == 0)
+ p_global->chrono_on |= 2;
+ if(!(p_global->chrono_on & 2))
+ return;
+ p_global->chrono_on = 0;
+ p_global->chrono = 0;
+ if(p_global->roomPersoType == PersonFlags::pftTyrann)
+ {
+ short vid = 272;
+ if(p_global->curRoomFlags & 0xC0)
+ {
+ vid += 2;
+ if((p_global->curRoomFlags & 0xC0) != 0x80)
+ {
+ vid += 2;
+ mort(vid);
+ return;
+ }
+ }
+ if(p_global->areaNum == Areas::arUluru || p_global->areaNum == Areas::arTamara)
+ {
+ mort(vid);
+ return;
+ }
+ vid++;
+ mort(vid);
+ return;
+ }
+ if(p_global->roomNum == 2817)
+ {
+ suis_moi(5);
+ p_global->gameFlags |= GameFlags::gfFlag40;
+ dialautoon();
+ }
+ else
+ eloirevient();
+ p_global->eventType = EventType::etEvent10;
+ showevents();
+}
+void chronoon(short t)
+{
+ p_global->chrono = t;
+ p_global->chrono_on = 1;
+}
+void prechargephrases(short vid)
+{
+ int num;
+ dial_t *dial;
+ perso_t *perso = &kPersons[PER_MORKUS];
+ if(vid == 170)
+ perso = &kPersons[PER_UNKN_156];
+ p_global->perso_ptr = perso;
+ p_global->dialogType = DialogType::dtInspect;
+ num = (perso->id << 3) | p_global->dialogType;
+ dial = (dial_t*)GetElem(gameDialogs, num);
+ dialoscansvmas(dial);
+}
+void effet1()
+{
+ debug(__FUNCTION__);
+ int x, y;
+ short i;
+ short dy, ny;
+ rectanglenoir32();
+ if(!doubled)
+ {
+ setRS1(0, 0, 16 - 1, 4 - 1);
+ y = p_mainview->norm.dst_top;
+ for(i = 16;i <= 96;i += 4)
+ {
+ for(x = p_mainview->norm.dst_left;x < p_mainview->norm.dst_left + 320;x += 16)
+ {
+ setRD1(x, y + i, x + 16 - 1, y + i + 4 - 1);
+ CLBlitter_CopyViewRect(p_view2, &ScreenView, &rect_src, &rect_dst);
+ setRD1(x, y + 192 - i, x + 16 - 1, y + 192 - i + 4 - 1);
+ CLBlitter_CopyViewRect(p_view2, &ScreenView, &rect_src, &rect_dst);
+ }
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ }
+ else
+ {
+ setRS1(0, 0, 16 * 2 - 1, 4 * 2 - 1);
+ y = p_mainview->zoom.dst_top;
+ for(i = 16 * 2;i <= 96 * 2;i += 4 * 2)
+ {
+ for(x = p_mainview->zoom.dst_left;x < p_mainview->zoom.dst_left + 320 * 2;x += 16 * 2)
+ {
+ setRD1(x, y + i, x + 16 * 2 - 1, y + i + 4 * 2 - 1);
+ CLBlitter_CopyViewRect(p_view2, &ScreenView, &rect_src, &rect_dst);
+ setRD1(x, y + 192 * 2 - i, x + 16 * 2 - 1, y + 192 * 2 - i + 4 * 2 - 1);
+ CLBlitter_CopyViewRect(p_view2, &ScreenView, &rect_src, &rect_dst);
+ }
+ wait(1);
+ }
+ }
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ p_mainview->norm.height = 2;
+ p_mainview->zoom.height = 4;
+ ny = p_mainview->norm.dst_top;
+ dy = p_mainview->zoom.dst_top;
+ for(i = 0;i < 100;i += 2)
+ {
+ p_mainview->norm.src_top = 99 - i;
+ p_mainview->zoom.src_top = 99 - i;
+ p_mainview->norm.dst_top = 99 - i + ny;
+ p_mainview->zoom.dst_top = (99 - i) * 2 + dy;
+ CLBlitter_CopyView2Screen(p_mainview);
+ p_mainview->norm.src_top = 100 + i;
+ p_mainview->zoom.src_top = 100 + i;
+ p_mainview->norm.dst_top = 100 + i + ny;
+ p_mainview->zoom.dst_top = (100 + i) * 2 + dy;
+ CLBlitter_CopyView2Screen(p_mainview);
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ p_mainview->norm.height = 200;
+ p_mainview->zoom.height = 400;
+ p_mainview->norm.src_top = 0;
+ p_mainview->zoom.src_top = 0;
+ p_mainview->norm.dst_top = ny;
+ p_mainview->zoom.dst_top = dy;
+ p_global->ff_F1 = 0;
+}
+void effet2()
+{
+ debug(__FUNCTION__);
+ static int eff2pat = 0;
+ if(p_global->ff_103 == 69)
+ {
+ effet4();
+ return;
+ }
+ switch(++eff2pat)
+ {
+ case 1:
+ {
+ static short pattern[] = {0, 1, 2, 3, 7, 11, 15, 14, 13, 12, 8, 4, 5, 6, 10, 9};
+ colimacon(pattern);
+ break;
+ }
+ case 2:
+ {
+ static short pattern[] = {0, 15, 1, 14, 2, 13, 3, 12, 7, 8, 11, 4, 5, 10, 6, 9};
+ colimacon(pattern);
+ break;
+ }
+ case 3:
+ {
+ static short pattern[] = {0, 2, 5, 7, 8, 10, 13, 15, 1, 3, 4, 6, 9, 11, 12, 14};
+ colimacon(pattern);
+ break;
+ }
+ case 4:
+ {
+ static short pattern[] = {0, 3, 15, 12, 1, 7, 14, 8, 2, 11, 13, 4, 5, 6, 10, 9};
+ colimacon(pattern);
+ eff2pat = 0;
+ break;
+ }
+ }
+}
+void effet3()
+{
+ debug(__FUNCTION__);
+ unsigned short i, c;
+ CLPalette_GetLastPalette(oldPalette);
+ for(i = 0;i < 6;i++)
+ {
+ for(c = 0;c < 256;c++)
+ {
+ newColor.r = oldPalette[c].r >> i;
+ newColor.g = oldPalette[c].g >> i;
+ newColor.b = oldPalette[c].b >> i;
+ CLPalette_SetRGBColor(newPalette, c, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(1);
+ }
+ CLBlitter_CopyView2Screen(p_mainview);
+ for(i = 0;i < 6;i++)
+ {
+ for(c = 0;c < 256;c++)
+ {
+ newColor.r = global_palette[c].r >> (5 - i);
+ newColor.g = global_palette[c].g >> (5 - i);
+ newColor.b = global_palette[c].b >> (5 - i);
+ CLPalette_SetRGBColor(newPalette, c, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(1);
+ }
+}
+void effet4()
+{
+ debug(__FUNCTION__);
+ unsigned char *scr, *pix, *r24, *r25, *r30, c;
+ short i;
+ short x, y;
+ short w, h, ww;
+ short r17, r23, r16, r18, r19, r22, r27, r31;
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ w = ScreenView.width;
+ h = ScreenView.height;
+ ww = ScreenView.pitch;
+ if(!doubled)
+ {
+ x = p_mainview->norm.dst_left;
+ y = p_mainview->norm.dst_top;
+ for(i = 32;i > 0;i -= 2)
+ {
+ scr = ScreenView.p_buffer;
+ scr += (y + 16) * ww + x;
+ pix = p_mainview->p_buffer + 16 * 640;
+ r17 = 320 / i;
+ r23 = 320 - 320 / i * i; //TODO: 320 % i ?
+ r16 = 160 / i;
+ r18 = 160 - 160 / i * i; //TODO: 160 % i ?
+ for(r19 = r16;r19 > 0;r19--)
+ {
+ r24 = scr;
+ r25 = pix;
+ for(r22 = r17;r22 > 0;r22--)
+ {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for(r27 = i;r27 > 0;r27--)
+ {
+ for(r31 = i;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - i;
+ }
+ r24 += i;
+ }
+ if(r23)
+ {
+ c = *r25;
+ r30 = r24;
+ for(r27 = i;r27 > 0;r27--)
+ {
+ for(r31 = r23;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - r23;
+ }
+ }
+ scr += i * ww;
+ pix += i * 640;
+ }
+ if(r18)
+ {
+ r24 = scr;
+ r25 = pix;
+ for(r22 = r17;r22 > 0;r22--)
+ {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for(r27 = r18;r27 > 0;r27--)
+ {
+ for(r31 = i;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - i;
+ }
+ r24 += i;
+ }
+ if(r23)
+ {
+ c = *r25;
+ r30 = r24;
+ for(r27 = r18;r27 > 0;r27--)
+ {
+ for(r31 = r23;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - r23;
+ }
+ }
+ }
+ CLBlitter_UpdateScreen();
+ wait(3);
+ }
+ }
+ else
+ {
+ x = p_mainview->zoom.dst_left;
+ y = p_mainview->zoom.dst_top;
+ for(i = 32;i > 0;i -= 2)
+ {
+ scr = ScreenView.p_buffer;
+ scr += (y + 16 * 2) * ww + x;
+ pix = p_mainview->p_buffer + 16 * 640;
+ r17 = 320 / i;
+ r23 = 320 % i;
+ r16 = 160 / i;
+ r18 = 160 % i;
+ for(r19 = r16;r19 > 0;r19--)
+ {
+ r24 = scr;
+ r25 = pix;
+ for(r22 = r17;r22 > 0;r22--)
+ {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for(r27 = i * 2;r27 > 0;r27--)
+ {
+ for(r31 = i * 2;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - i * 2;
+ }
+ r24 += i * 2;
+ }
+ if(r23)
+ {
+ c = *r25;
+ r30 = r24;
+ for(r27 = i * 2;r27 > 0;r27--)
+ {
+ for(r31 = r23 * 2;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - r23 * 2;
+ }
+ }
+ scr += i * ww * 2;
+ pix += i * 640;
+ }
+ if(r18)
+ {
+ r24 = scr;
+ r25 = pix;
+ for(r22 = r17;r22 > 0;r22--)
+ {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for(r27 = r18 * 2;r27 > 0;r27--)
+ {
+ for(r31 = i * 2;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - i * 2;
+ }
+ r24 += i * 2;
+ }
+ if(r23)
+ {
+ c = *r25;
+ r30 = r24;
+ for(r27 = i * 2;r27 > 0;r27--)
+ {
+ for(r31 = r23 * 2;r31 > 0;r31--)
+ *r30++ = c;
+ r30 += ww - r23 * 2;
+ }
+ }
+ }
+ wait(3);
+ }
+ }
+ CLBlitter_CopyView2Screen(p_mainview);
+}
+void ClearScreen()
+{
+ unsigned char *scr;
+ short x, y, xx, yy;
+ short w, h, ww;
+ w = ScreenView.width;
+ h = ScreenView.height;
+ ww = ScreenView.pitch;
+ if(!doubled)
+ {
+ x = p_mainview->norm.dst_left;
+ y = p_mainview->norm.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16) * ww + x;
+ for(yy = 0;yy < 160;yy++)
+ {
+ for(xx = 0;xx < 320;xx++)
+ *scr++ = 0;
+ scr += ww - 320;
+ }
+ }
+ else
+ {
+ x = p_mainview->zoom.dst_left;
+ y = p_mainview->zoom.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 32) * ww + x;
+ for(yy = 0;yy < 160;yy++)
+ {
+ for(xx = 0;xx < 320;xx++)
+ {
+ scr[0] = 0;
+ scr[1] = 0;
+ scr[ww] = 0;
+ scr[ww + 1] = 0;
+ scr += 2;
+ }
+ scr += (ww - 320) * 2;
+ }
+ }
+ CLBlitter_UpdateScreen();
+}
+void colimacon(short pattern[16])
+{
+ unsigned char *scr, *pix;
+ short x, y, xx, yy;
+ short w, h, ww;
+ short i, j, p, r27, r25;
+ w = ScreenView.width;
+ h = ScreenView.height;
+ ww = ScreenView.pitch;
+ if(!doubled)
+ {
+ x = p_mainview->norm.dst_left;
+ y = p_mainview->norm.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16) * ww + x;
+ for(i = 0;i < 16;i++)
+ {
+ p = pattern[i];
+ r27 = p % 4 + p / 4 * ww;
+ for(j = 0;j < 320 * 160 / 16;j++)
+ scr[j / (320 / 4) * ww * 4 + j % (320 / 4) * 4 + r27] = 0;
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ }
+ else
+ {
+ x = p_mainview->zoom.dst_left;
+ y = p_mainview->zoom.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16 * 2) * ww + x;
+ for(i = 0;i < 16;i++)
+ {
+ p = pattern[i];
+ r27 = p % 4 * 2 + p / 4 * ww * 2;
+ for(j = 0;j < 320 * 160 / 16;j++)
+ {
+ unsigned char *sc = &scr[j / (320 / 4) * ww * 4 * 2 + j % (320 / 4) * 4 * 2 + r27];
+ sc[0] = 0;
+ sc[1] = 0;
+ sc[ww] = 0;
+ sc[ww + 1] = 0;
+ }
+ wait(1);
+ }
+ }
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ if(!doubled)
+ {
+ pix = p_mainview->p_buffer;
+ x = p_mainview->norm.dst_left;
+ y = p_mainview->norm.dst_top;
+ pix += 640 * 16;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16) * ww + x;
+ for(i = 0;i < 16;i++)
+ {
+ p = pattern[i];
+ r25 = p % 4 + p / 4 * 640;
+ r27 = p % 4 + p / 4 * ww;
+ for(j = 0;j < 320 * 160 / 16;j++)
+ scr[j / (320 / 4) * ww * 4 + j % (320 / 4) * 4 + r27] =
+ pix[j / (320 / 4) * 640 * 4 + j % (320 / 4) * 4 + r25];
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ }
+ else
+ {
+ pix = p_mainview->p_buffer;
+ x = p_mainview->zoom.dst_left;
+ y = p_mainview->zoom.dst_top;
+ pix += 640 * 16;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16 * 2) * ww + x;
+ for(i = 0;i < 16;i++)
+ {
+ p = pattern[i];
+ r25 = p % 4 + p / 4 * 640;
+ r27 = p % 4 * 2 + p / 4 * ww * 2;
+ for(j = 0;j < 320 * 160 / 16;j++)
+ {
+ unsigned char c = pix[j / (320 / 4) * 640 * 4 + j % (320 / 4) * 4 + r25];
+ unsigned char *sc = &scr[j / (320 / 4) * ww * 4 * 2 + j % (320 / 4) * 4 * 2 + r27];
+ sc[0] = c;
+ sc[1] = c;
+ sc[ww] = c;
+ sc[ww + 1] = c;
+ }
+ wait(1);
+ }
+ }
+}
+void fadetoblack(int delay)
+{
+ short i, j;
+ CLPalette_GetLastPalette(oldPalette);
+ for(i = 0;i < 6;i++)
+ {
+ for(j = 0;j < 256;j++)
+ {
+ newColor.r = oldPalette[j].r >> i;
+ newColor.g = oldPalette[j].g >> i;
+ newColor.b = oldPalette[j].b >> i;
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(delay);
+ }
+}
+void fadetoblack128(int delay)
+{
+ short i, j;
+ CLPalette_GetLastPalette(oldPalette);
+ for(i = 0;i < 6;i++)
+ {
+ for(j = 0;j < 129;j++) //TODO: wha?
+ {
+ newColor.r = oldPalette[j].r >> i;
+ newColor.g = oldPalette[j].g >> i;
+ newColor.b = oldPalette[j].b >> i;
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 128);
+ wait(delay);
+ }
+}
+void fadefromblack128(int delay)
+{
+ short i, j;
+ for(i = 0;i < 6;i++)
+ {
+ for(j = 0;j < 129;j++) //TODO: wha?
+ {
+ newColor.r = global_palette[j].r >> (5 - i);
+ newColor.g = global_palette[j].g >> (5 - i);
+ newColor.b = global_palette[j].b >> (5 - i);
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 128);
+ wait(delay);
+ }
+}
+void rectanglenoir32()
+{
+ // blacken 32x32 rectangle
+ int i;
+ int *pix = (int*)p_view2_buf;
+ for(i = 0;i < 32;i++)
+ {
+ pix[0] = 0;
+ pix[1] = 0;
+ pix[2] = 0;
+ pix[3] = 0;
+ pix[4] = 0;
+ pix[5] = 0;
+ pix[6] = 0;
+ pix[7] = 0;
+ pix += 32 / 4;
+ }
+}
+void setRS1(short sx, short sy, short ex, short ey)
+{
+ rect_src.sx = sx;
+ rect_src.sy = sy;
+ rect_src.ex = ex;
+ rect_src.ey = ey;
+}
+void setRD1(short sx, short sy, short ex, short ey)
+{
+ rect_dst.sx = sx;
+ rect_dst.sy = sy;
+ rect_dst.ex = ex;
+ rect_dst.ey = ey;
+}
+void wait(int howlong)
+{
+ int t2, t = TickCount();
+#ifdef EDEN_DEBUG
+ howlong *= 10;
+#endif
+ for (t2 = t; t2 - t < howlong; t2 = TickCount()) g_system->delayMillis(10); // waste time
+}
+void effetpix()
+{
+ debug(__FUNCTION__);
+ unsigned char *scr, *pix;
+ short x, y, xx, yy;
+ short w, h, ww;
+ short i, j, p, r25, r18, r31, r30; //TODO: change to xx/yy
+ unsigned char r24, r23; //TODO: change to p0/p1
+ short r26, r27, r20;
+ w = ScreenView.width;
+ h = ScreenView.height;
+ ww = ScreenView.pitch;
+ r25 = ww * 80;
+ r18 = 640 * 80;
+ pix = p_mainview->p_buffer + 16 * 640;
+ if(!doubled)
+ {
+ x = p_mainview->norm.dst_left;
+ y = p_mainview->norm.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16) * ww + x;
+ }
+ else
+ {
+ x = p_mainview->zoom.dst_left;
+ y = p_mainview->zoom.dst_top;
+ scr = ScreenView.p_buffer;
+ scr += (y + 16 * 2) * ww + x;
+ r25 *= 2;
+ }
+ r20 = 0x4400; //TODO
+ r27 = 1;
+ r26 = 0;
+ do
+ {
+ char r8 = r27 & 1;
+ r27 >>= 1;
+ if(r8)
+ r27 ^= r20;
+ if(r27 < 320 * 80)
+ {
+ r31 = r27 / 320;
+ r30 = r27 % 320;
+ if(doubled)
+ {
+ r31 *= 2;
+ r30 *= 2;
+ scr[r31 * ww + r30] = 0;
+ scr[r31 * ww + r30 + 1] = 0;
+ scr[r31 * ww + r25 + r30] = 0;
+ scr[r31 * ww + r25 + r30 + 1] = 0;
+ r31++;
+ scr[r31 * ww + r30] = 0;
+ scr[r31 * ww + r30 + 1] = 0;
+ scr[r31 * ww + r25 + r30] = 0;
+ scr[r31 * ww + r25 + r30 + 1] = 0;
+ if(++r26 == 960)
+ {
+ wait(1);
+ r26 = 0;
+ }
+ }
+ else
+ {
+ scr[r31 * ww + r30] = 0;
+ scr[r31 * ww + r25 + r30] = 0;
+ if(++r26 == 960)
+ {
+ CLBlitter_UpdateScreen();
+ wait(1);
+ r26 = 0;
+ }
+ }
+ }
+ }
+ while(r27 != 1);
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ r20 = 0x4400;
+ r27 = 1;
+ r26 = 0;
+ do
+ {
+ char r8 = r27 & 1;
+ r27 >>= 1;
+ if(r8)
+ r27 ^= r20;
+ if(r27 < 320 * 80)
+ {
+ r31 = r27 / 320;
+ r30 = r27 % 320;
+ r24 = pix[r31 * 640 + r30];
+ r23 = pix[r31 * 640 + r18 + r30];
+ if(doubled)
+ {
+ r31 *= 2;
+ r30 *= 2;
+ scr[r31 * ww + r30] = r24;
+ scr[r31 * ww + r30 + 1] = r24;
+ scr[r31 * ww + r25 + r30] = r23;
+ scr[r31 * ww + r25 + r30 + 1] = r23;
+ r31++;
+ scr[r31 * ww + r30] = r24;
+ scr[r31 * ww + r30 + 1] = r24;
+ scr[r31 * ww + r25 + r30] = r23;
+ scr[r31 * ww + r25 + r30 + 1] = r23;
+ if(++r26 == 960)
+ {
+ wait(1);
+ r26 = 0;
+ }
+ }
+ else
+ {
+ scr[r31 * ww + r30] = r24;
+ scr[r31 * ww + r25 + r30] = r23;
+ if(++r26 == 960)
+ {
+ CLBlitter_UpdateScreen();
+ wait(1);
+ r26 = 0;
+ }
+ }
+ }
+ }
+ while(r27 != 1);
+ assert(ScreenView.pitch == 320);
+}
+////// datfile.c
+void verifh(void *ptr)
+{
+ unsigned char sum = 0;
+ unsigned char *data;
+ unsigned char *head = (unsigned char*)ptr;
+ unsigned short h0, h3;
+ short i;
+ char h2;
+ for(i = 0;i < 6;i++)
+ sum += *head++;
+ if(sum != 0xAB)
+ return;
+ debug("* Begin unpacking resource");
+ head -= 6;
+ h0 = PLE16(head); head += 2;
+ h2 = *head++;
+ h3 = PLE16(head); head += 2;
+ data = h0 + head + 26;
+ h3 -= 6;
+ head += h3;
+ for(;h3;h3--)
+ *data-- = *head--;
+ head = data + 1;
+ data = (unsigned char*)ptr;
+ Expand_hsq(head, data);
+}
+void openbigfile()
+{
+ assert(sizeof(pakfile_t) == 25);
+ long size = 0x10000;
+ CLFile_MakeStruct(0, 0, "EDEN.DAT", &bigfilespec);
+ CLFile_Open(&bigfilespec, 1, h_bigfile);
+ CLFile_Read(h_bigfile, bigfile_header, &size);
+ p_hnmcontext = CLHNM_New(128);
+ CLHNM_SetFile(p_hnmcontext, &h_bigfile);
+}
+void closebigfile()
+{
+ CLFile_Close(h_bigfile);
+}
+void loadfile(unsigned short num, void *buffer)
+{
+ short retry, res = 1;
+ assert(num < bigfile_header->count);
+ for(retry = 0;res && retry < 5;retry++)
+ {
+ pakfile_t *file = &bigfile_header->files[num];
+ long size = PLE32(&file->size);
+ long offs = PLE32(&file->offs);
+ debug("* Loading resource %d (%s) at 0x%X, %d bytes", num, file->name, offs, size);
+ CLFile_SetPosition(h_bigfile, fsFromStart, offs);
+ CLFile_Read(h_bigfile, buffer, &size);
+ res = 0;
+ }
+ if(res)
+ quit_flag = 1;
+}
+void shnmfl(unsigned short num)
+{
+ int res;
+ assert(num + 484 < bigfile_header->count);
+ pakfile_t *file = &bigfile_header->files[num + 484];
+ int size = PLE32(&file->size);
+ int offs = PLE32(&file->offs);
+ debug("* Loading movie %d (%s) at 0x%X, %d bytes", num, file->name, offs, size);
+ CLHNM_SetPosIntoFile(p_hnmcontext, offs);
+}
+int ssndfl(unsigned short num)
+{
+ int res;
+ assert(num + 660 < bigfile_header->count);
+ pakfile_t *file = &bigfile_header->files[num + 660];
+ long size = PLE32(&file->size);
+ long offs = PLE32(&file->offs);
+ if(soundAllocated)
+ {
+ CLMemory_Free(voiceSamplesBuffer);
+ soundAllocated = 0; //TODO: bug??? no alloc
+ }
+ else
+ {
+ voiceSamplesBuffer = CLMemory_Alloc(size);
+ soundAllocated = 1;
+ }
+ CLFile_SetPosition(h_bigfile, 1, offs);
+ CLFile_Read(h_bigfile, voiceSamplesBuffer, &size);
+ return size;
+
+}
+#if 1
+void ConvertIcons(icon_t *icon, int count)
+{
+ int i;
+ for (i = 0; i < count; i++, icon++)
+ {
+ icon->sx = BE16(icon->sx);
+ icon->sy = BE16(icon->sy);
+ icon->ex = BE16(icon->ex);
+ icon->ey = BE16(icon->ey);
+ icon->cursor_id = BE16(icon->cursor_id);
+ icon->object_id = BE32(icon->object_id);
+ icon->action_id = BE32(icon->action_id);
+ }
+}
+
+void ConvertLinks(room_t *room, int count)
+{
+ int i;
+ for (i = 0; i < count; i++, room++)
+ {
+ room->bank = BE16(room->bank);
+ room->party = BE16(room->party);
+ }
+}
+
+void ConvertMacToPC()
+{
+ // Conert all mac (big-endian) resources to native format
+ ConvertIcons(gameIcons, 136);
+ ConvertLinks(gameRooms, 424);
+ // Array of longs
+ int *p = (int*)gameLipsync;
+ for(int i = 0;i < 7240 / 4;i++)
+ p[i] = BE32(p[i]);
+}
+#endif
+
+void loadpermfiles()
+{
+ loadfile(2498, gameIcons);
+ loadfile(2497, gameRooms);
+ loadfile(2486, gameLipsync);
+ loadfile(0, main_bank_buf);
+ loadfile(402, gameFont);
+ loadfile(404, gameDialogs);
+ loadfile(403, gameConditions);
+#if 1
+ ConvertMacToPC();
+#endif
+}
+char ReadDataSync(unsigned short num)
+{
+ long pos, len;
+ pos = PLE32(gameLipsync + num * 4);
+ len = 1024;
+ if(pos != -1)
+ {
+ loadpartoffile(1936, gameLipsync + 7260, pos, len);
+ return 1;
+ }
+ return 0;
+}
+void loadpartoffile(unsigned short num, void *buffer, long pos, long len)
+{
+ short res;
+ assert(num < bigfile_header->count);
+ pakfile_t *file = &bigfile_header->files[num];
+ long offs = PLE32(&file->offs);
+ debug("* Loading partial resource %d (%s) at 0x%X(+0x%X), %d bytes", num, file->name, offs, pos, len);
+ CLFile_SetPosition(h_bigfile, 1, offs + pos);
+ CLFile_Read(h_bigfile, buffer, &len);
+}
+void Expand_hsq(void *input, void *output)
+{
+ unsigned char *src = (unsigned char*)input;
+ unsigned char *dst = (unsigned char*)output;
+ unsigned char *ptr;
+ unsigned short bit; // bit
+ unsigned short queue = 0; // queue
+ unsigned short len = 0;
+ short ofs;
+#define GetBit \
+ bit = queue & 1; \
+ queue >>= 1; \
+ if(!queue) \
+ { \
+ queue = (src[1] << 8) | src[0]; src += 2; \
+ bit = queue & 1; \
+ queue = (queue >> 1) | 0x8000; \
+ }
+
+ for(;;)
+ {
+ GetBit;
+ if(bit)
+ *dst++ = *src++;
+ else
+ {
+ len = 0;
+ GetBit;
+ if(!bit)
+ {
+ GetBit;
+ len = (len << 1) | bit;
+ GetBit;
+ len = (len << 1) | bit;
+ ofs = 0xFF00 | *src++; //TODO: -256
+ }
+ else
+ {
+ ofs = (src[1] << 8) | src[0]; src += 2;
+ len = ofs & 7;
+ ofs = (ofs >> 3) | 0xE000;
+ if(!len)
+ {
+ len = *src++;
+ if(!len)
+ break;
+ }
+ }
+ ptr = dst + ofs;
+ len += 2;
+ while(len--)
+ *dst++ = *ptr++;
+ }
+ }
+}
+//////
+void ajouinfo(unsigned char info)
+{
+ unsigned char idx = p_global->next_info_idx;
+ if(kPersons[PER_MESSAGER].roomNum)
+ info |= 0x80;
+ info_list[idx] = info;
+ if(idx == p_global->last_info_idx)
+ p_global->last_info = info;
+ idx++; if(idx == 16) idx = 0;
+ p_global->next_info_idx = idx;
+}
+void unlockinfo()
+{
+ unsigned char idx;
+ for(idx = 0;idx < 16;idx++)
+ {
+ if(info_list[idx] != 0xFF)
+ info_list[idx] &= ~0x80;
+ }
+ p_global->last_info &= ~0x80;
+}
+void nextinfo()
+{
+ do
+ {
+ unsigned char idx = p_global->last_info_idx;
+ info_list[idx] = 0;
+ idx++; if(idx == 16) idx = 0;
+ p_global->last_info_idx = idx;
+ p_global->last_info = info_list[idx];
+ }
+ while(p_global->last_info == 0xFF);
+}
+void delinfo(unsigned char info)
+{
+ unsigned char idx;
+ for(idx = 0;idx < 16;idx++)
+ {
+ if((info_list[idx] & ~0x80) == info)
+ {
+ info_list[idx] = 0xFF;
+ if(idx == p_global->last_info_idx)
+ nextinfo();
+ break;
+ }
+ }
+}
+void updateinfolist()
+{
+ int idx;
+ for(idx = 0;idx < 16;idx++)
+ info_list[idx] = 0;
+}
+void init_globals()
+{
+ gameIcons[16].cursor_id |= 0x8000;
+
+ p_global->areaNum = Areas::arMo;
+ p_global->areaVisitCount = 1;
+ p_global->menuItemIdLo = 0;
+ p_global->menuItemIdHi = 0;
+ p_global->randomNumber = 0;
+ p_global->gameTime = 0;
+ p_global->gameDays = 0;
+ p_global->chrono = 0;
+ p_global->eloiDepartureDay = 0;
+ p_global->roomNum = 259;
+ p_global->newRoomNum = 0;
+ p_global->phaseNum = 0;
+ p_global->metPersonsMask1 = 0;
+ p_global->party = 0;
+ p_global->partyOutside = 0;
+ p_global->metPersonsMask2 = 0;
+ p_global->__UNUSED_1C = 0;
+ p_global->phaseActionsCount = 0;
+ p_global->curAreaFlags = 0;
+ p_global->curItemsMask = 0;
+ p_global->curPowersMask = 0;
+ p_global->curPersoItems = 0;
+ p_global->curPersoPowers = 0;
+ p_global->wonItemsMask = 0;
+ p_global->wonPowersMask = 0;
+ p_global->stepsToFindAppleFast = 0;
+ p_global->stepsToFindAppleNormal = 0;
+ p_global->roomPersoItems = 0;
+ p_global->roomPersoPowers = 0;
+ p_global->gameFlags = 0;
+ p_global->curVideoNum = 0;
+ p_global->morkusSpyVideoNum1 = 89;
+ p_global->morkusSpyVideoNum2 = 88;
+ p_global->morkusSpyVideoNum3 = 83;
+ p_global->morkusSpyVideoNum4 = 94;
+ p_global->newMusicType = MusicType::mtDontChange;
+ p_global->ff_43 = 0;
+ p_global->videoSubtitleIndex = 0;
+ p_global->partyInstruments = 0;
+ p_global->monkGotRing = 0;
+ p_global->chrono_on = 0;
+ p_global->curRoomFlags = 0;
+ p_global->endGameFlag = 0;
+ p_global->last_info = 0;
+ p_global->autoDialog = 0;
+ p_global->worldTyrannSighted = 0;
+ p_global->ff_4D = 0;
+ p_global->ff_4E = 0;
+ p_global->worldGaveGold = 0;
+ p_global->worldHasTriceraptors = 0;
+ p_global->worldHasVelociraptors = 0;
+ p_global->worldHasTyrann = 0;
+ p_global->ff_53 = 0;
+ p_global->ff_54 = 0;
+ p_global->ff_55 = 0;
+ p_global->ff_56 = 0;
+ p_global->textToken1 = 0;
+ p_global->textToken2 = 0;
+ p_global->eloiHaveNews = 0;
+ p_global->dialogFlags = 0;
+ p_global->curAreaType = 0;
+ p_global->curCitadelLevel = 0;
+ p_global->newLocation = 0;
+ p_global->prevLocation = 0;
+ p_global->curPersoFlags = 0;
+ p_global->ff_60 = 0;
+ p_global->eventType = EventType::etEvent5;
+ p_global->ff_62 = 0;
+ p_global->curObjectId = 0;
+ p_global->curObjectFlags = 0;
+ p_global->ff_65 = 1;
+ p_global->roomPersoType = 0;
+ p_global->roomPersoFlags = 0;
+ p_global->narratorSequence = 0;
+ p_global->ff_69 = 0;
+ p_global->ff_6A = 0;
+ p_global->fresqNumber = 0;
+ p_global->ff_6C = 0;
+ p_global->ff_6D = 0;
+ p_global->labyrinthDirections = 0;
+ p_global->labyrinthRoom = 0;
+ p_global->curPersoAnimPtr = 0;
+ p_global->perso_img_bank = 0;
+ p_global->roomImgBank = 0;
+ p_global->persoBackgroundBankIdx = 55;
+ p_global->ff_D4 = 0;
+ p_global->fresqWidth = 0;
+ p_global->fresqImgBank = 0;
+ p_global->ff_DA = 0;
+ p_global->ff_DC = 0;
+ p_global->room_x_base = 0;
+ p_global->ff_E0 = 0;
+ p_global->dialogType = 0;
+ p_global->ff_E4 = 0;
+ p_global->currentMusicNum = 0;
+ p_global->textNum = 0;
+ p_global->travelTime = 0;
+ p_global->ff_EC = 0;
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ p_global->oldDisplayFlags = 1;
+ p_global->drawFlags = 0;
+ p_global->ff_F1 = 0;
+ p_global->ff_F2 = 0;
+ p_global->menuFlags = 0;
+ p_global->ff_F5 = 0;
+ p_global->ff_F6 = 0;
+ p_global->ff_F7 = 0;
+ p_global->ff_F8 = 0;
+ p_global->ff_F9 = 0;
+ p_global->ff_FA = 0;
+ p_global->animationFlags = 0;
+ p_global->__UNUSED_FC = 0;
+ p_global->giveobj1 = 0;
+ p_global->giveobj2 = 0;
+ p_global->giveobj3 = 0;
+ p_global->ff_100 = 0;
+ p_global->roomVidNum = 0;
+ p_global->ff_102 = 0;
+ p_global->ff_103 = 0;
+ p_global->roomBgBankNum = 0;
+ p_global->valleyVidNum = 0;
+ p_global->updatePaletteFlag = 0;
+ p_global->inventoryScrollPos = 0;
+ p_global->obj_count = 0;
+ p_global->ff_109 = 0;
+ p_global->textBankIndex = 69;
+ p_global->cita_area_num = 0;
+ p_global->ff_113 = 0;
+ p_global->lastSalNum = 0;
+ p_global->__UNUSED_70 = 0;
+ p_global->dialog_ptr = 0;
+ p_global->tape_ptr = tapes;
+ p_global->next_dialog_ptr = 0;
+ p_global->narrator_dialog_ptr = 0;
+ p_global->last_dialog_ptr = 0;
+ p_global->nextRoomIcon = 0;
+ p_global->phraseBufferPtr = 0;
+ p_global->__UNUSED_90 = 0;
+ p_global->__UNUSED_94 = 0;
+ p_global->room_ptr = 0;
+ p_global->area_ptr = 0;
+ p_global->last_area_ptr = 0;
+ p_global->cur_area_ptr = 0;
+ p_global->cita_area_firstRoom = 0;
+ p_global->perso_ptr = 0;
+ p_global->room_perso = 0;
+ p_global->last_info_idx = 0;
+ p_global->next_info_idx = 0;
+ p_global->iconsIndex = 16;
+ p_global->persoSpritePtr = 0;
+ p_global->numGiveObjs = 0;
+
+ rect_31C7A.sy = 0; //TODO: unused?
+ rect_31C7A.sx = 0;
+ rect_31C7A.ex = 320 - 1;
+ rect_31C7A.ey = 200 - 1;
+
+ initrect();
+
+ underSubtitlesScreenRect.sy = 0;
+ underSubtitlesScreenRect.sx = subtitles_x_scr_margin;
+ underSubtitlesScreenRect.ex = subtitles_x_scr_margin + subtitles_x_width - 1;
+ underSubtitlesScreenRect.ey = 176 - 1;
+
+ underSubtitlesBackupRect.sy = 0;
+ underSubtitlesBackupRect.sx = subtitles_x_scr_margin;
+ underSubtitlesBackupRect.ex = subtitles_x_scr_margin + subtitles_x_width - 1;
+ underSubtitlesBackupRect.ey = 60 - 1;
+}
+void initrect()
+{
+ underTopBarScreenRect.sy = 0;
+ underTopBarScreenRect.sx = 0;
+ underTopBarScreenRect.ex = 320 - 1;
+ underTopBarScreenRect.ey = 16 - 1;
+
+ underTopBarBackupRect.sy = 0;
+ underTopBarBackupRect.sx = 0;
+ underTopBarBackupRect.ex = 320 - 1;
+ underTopBarBackupRect.ey = 16 - 1;
+
+ underBottomBarScreenRect.sy = 176;
+ underBottomBarScreenRect.sx = 0;
+ underBottomBarScreenRect.ex = 320 - 1;
+ underBottomBarScreenRect.ey = 200 - 1; //TODO: original bug? this cause crash in copyrect (this, underBottomBarBackupRect)
+
+ underBottomBarBackupRect.sy = 16;
+ underBottomBarBackupRect.sx = 0;
+ underBottomBarBackupRect.ex = 320 - 1;
+ underBottomBarBackupRect.ey = 40 - 1;
+}
+void closesalle()
+{
+ if(p_global->displayFlags & DisplayFlags::dfPanable)
+ {
+ p_global->displayFlags &= ~DisplayFlags::dfPanable;
+ resetscroll();
+ }
+}
+void afsalle1(room_t *room)
+{
+ unsigned char *ptr = (unsigned char*)GetElem(sal_buf, room->ff_0 - 1);
+ ptr++;
+ for(;;)
+ {
+ unsigned char b0, b1;
+ short index, x, y, ex, ey;
+ b0 = *ptr++;
+ b1 = *ptr++;
+ index = (b1 << 8) | b0;
+ if(index == -1)
+ break;
+ if(index > 0)
+ {
+ x = *ptr++ | (((b1 & 0x2) >> 1) << 8); //TODO: check me
+ y = *ptr++;
+ ptr++;
+ index &= 0x1FF;
+ if(!(p_global->displayFlags & 0x80))
+ {
+ if(index == 1 || p_global->ff_F7)
+ noclipax_avecnoir(index - 1, x, y);
+ }
+ p_global->ff_F7 = 0;
+ continue;
+ }
+ if(b1 & 0x40)
+ {
+ if(b1 & 0x20)
+ {
+ char addIcon = 0;
+ icon_t *icon = p_global->nextRoomIcon;
+ if(b0 < 4)
+ {
+ if(p_global->room_ptr->exits[b0])
+ addIcon = 1;
+ }
+ else if(b0 > 229)
+ {
+ if(p_global->partyOutside & (1 << (b0 - 230)))
+ addIcon = 1;
+ }
+ else if(b0 >= 100)
+ {
+debug("add object %d", b0 - 100);
+ if(objecthere(b0 - 100))
+ {
+ addIcon = 1;
+ p_global->ff_F7 = -1;
+ }
+ }
+ else
+ addIcon = 1;
+ if(addIcon)
+ {
+ icon->action_id = b0;
+ icon->object_id = b0;
+ icon->cursor_id = kActionCursors[b0];
+ x = PLE16(ptr); ptr += 2;
+ y = PLE16(ptr); ptr += 2;
+ ex = PLE16(ptr); ptr += 2;
+ ey = PLE16(ptr); ptr += 2;
+ x += p_global->room_x_base;
+ ex += p_global->room_x_base;
+ debug("add hotspot at %3d:%3d - %3d:%3d, action = %d", x, y, ex, ey, b0);
+#ifdef EDEN_DEBUG
+ for (int iii = x; iii < ex; iii++) p_mainview_buf[y * 640 + iii] = p_mainview_buf[ey * 640 + iii] = (iii % 2) ? 0 : 255;
+ for (int iii = y; iii < ey; iii++) p_mainview_buf[iii * 640 + x] = p_mainview_buf[iii * 640 + ex] = (iii % 2) ? 0 : 255;
+#endif
+ icon->sx = x;
+ icon->sy = y;
+ icon->ex = ex;
+ icon->ey = ey;
+ p_global->nextRoomIcon = ++icon;
+ icon->sx = -1;
+ }
+ else
+ ptr += 8;
+ }
+ else
+ ptr += 8;
+ }
+ else
+ ptr += 8;
+ }
+}
+void afsalle()
+{
+ room_t *room = p_global->room_ptr;
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ p_global->room_x_base = 0;
+ p_global->roomBgBankNum = room->background;
+ if(room->flags & RoomFlags::rf08)
+ {
+ p_global->displayFlags |= DisplayFlags::dfFlag80;
+ if(room->flags & RoomFlags::rfPanable)
+ {
+ p_global->displayFlags |= DisplayFlags::dfPanable;
+ p_global->ff_F4 = 0;
+ rundcurs();
+ sauvefrises();
+ use_bank(room->bank - 1);
+ noclipax_avecnoir(0, 0, 16);
+ use_bank(room->bank);
+ noclipax_avecnoir(0, 320, 16);
+ afsalle1(room);
+ p_global->room_x_base = 320;
+ afsalle1(room + 1);
+ }
+ else
+ afsalle1(room);
+ }
+ else
+ {
+ //TODO: roomImgBank is garbage here!
+ debug("drawroom: room 0x%X using bank %d", p_global->roomNum, p_global->roomImgBank);
+ use_bank(p_global->roomImgBank);
+ afsalle1(room);
+ assert(ScreenView.pitch == 320);
+ }
+}
+void aflieu()
+{
+ no_perso();
+ if(!pomme_q)
+ {
+ p_global->iconsIndex = 16;
+ p_global->autoDialog = 0;
+ }
+ p_global->nextRoomIcon = &gameIcons[28];
+ afsalle();
+ needPaletteUpdate = 1;
+}
+void loadsal(short num)
+{
+ if(num == p_global->lastSalNum)
+ return;
+ p_global->lastSalNum = num;
+ loadfile(num + 419, sal_buf);
+}
+void specialoutside()
+{
+ if(p_global->last_area_ptr->type == AreaType::atValley && (p_global->party & PersonMask::pmLeader))
+ perso_ici(5);
+}
+void specialout()
+{
+ if(p_global->gameDays - p_global->eloiDepartureDay > 2)
+ {
+ if(eloirevientq() == 1)
+ eloirevient();
+ }
+ if(p_global->phaseNum >= 32 && p_global->phaseNum < 48)
+ if(p_global->newLocation == 9 || p_global->newLocation == 4 || p_global->newLocation == 24)
+ {
+ kPersons[PER_MESSAGER].roomNum = 263;
+ return;
+ }
+ if(p_global->phaseNum == 434)
+ if(p_global->newLocation == 5)
+ {
+ reste_ici(4);
+ kPersons[PER_BOURREAU].roomNum = 264;
+ return;
+ }
+ if(p_global->phaseNum < 400)
+ if((p_global->gameFlags & GameFlags::gfFlag4000) && p_global->prevLocation == 1
+ && (p_global->party & PersonMask::pmEloi) && p_global->curAreaType == AreaType::atValley)
+ eloipart();
+ if(p_global->phaseNum == 386)
+ if(p_global->prevLocation == 1
+ && (p_global->party & PersonMask::pmEloi) && p_global->areaNum == Areas::arCantura)
+ eloipart();
+}
+void specialin()
+{
+ if(!(p_global->party & PersonMask::pmEloi) && (p_global->partyOutside & PersonMask::pmEloi) && (p_global->roomNum & 0xFF) == 1)
+ {
+ suis_moi(5);
+ p_global->eloiHaveNews = 1;
+ }
+ if (p_global->roomNum == 288)
+ p_global->gameFlags |= GameFlags::gfFlag100 | GameFlags::gfFlag2000;
+ if(p_global->roomNum == 3075 && p_global->phaseNum == 546)
+ {
+ incphase1();
+ if(p_global->curItemsMask & 0x2000) // Morkus' tablet
+ {
+ bars_out();
+ playhnm(92);
+ gameRooms[129].exits[0] = 0;
+ gameRooms[129].exits[2] = 1;
+ p_global->roomNum = 3074;
+ kPersons[PER_MANGO].roomNum = 3074;
+ p_global->eventType = EventType::etEvent5;
+ maj_salle(p_global->roomNum);
+ return;
+ }
+ p_global->narratorSequence = 53;
+ }
+ if(p_global->roomNum == 1793 && p_global->phaseNum == 336)
+ eloipart();
+ if(p_global->roomNum == 259 && p_global->phaseNum == 129)
+ p_global->narratorSequence = 12;
+ if(p_global->roomNum >= 289 && p_global->roomNum < 359)
+ p_global->labyrinthDirections = kLabyrinthPath[(p_global->roomNum & 0xFF) - 33];
+ if(p_global->roomNum == 305 && p_global->prevLocation == 103)
+ p_global->gameFlags &= ~GameFlags::gfFlag2000;
+ if(p_global->roomNum == 304 && p_global->prevLocation == 105)
+ p_global->gameFlags &= ~GameFlags::gfFlag2000;
+ if(p_global->phaseNum < 226)
+ {
+ if(p_global->roomNum == 842)
+ p_global->gameFlags |= GameFlags::gfFlag2;
+ if(p_global->roomNum == 1072)
+ p_global->gameFlags |= GameFlags::gfFlag4;
+ if(p_global->roomNum == 1329)
+ p_global->gameFlags |= GameFlags::gfFlag8000;
+ }
+}
+void animpiece()
+{
+ room_t *room = p_global->room_ptr;
+ if(p_global->roomVidNum && p_global->ff_100 != 0xFF)
+ {
+ if(p_global->valleyVidNum || !room->level || (room->flags & RoomFlags::rfHasCitadel)
+ || room->level == p_global->ff_100)
+ {
+ bars_out();
+ p_global->updatePaletteFlag = 16;
+ if(!p_global->narratorSequence & 0x80) //TODO: bug? !() @ 100DC
+ p_global->ff_102 = 0;
+ if(!needToFade)
+ needToFade = room->flags & RoomFlags::rf02;
+ playhnm(p_global->roomVidNum);
+ return;
+ }
+ }
+ p_global->ff_F1 &= ~RoomFlags::rf04;
+}
+void getdino(room_t *room)
+{
+ assert(tab_2CEF0[4] == 0x25);
+ perso_t *perso = &kPersons[PER_UNKN_18C];
+ short *tab;
+ unsigned char persoType, r27;
+ short bank;
+ room->flags &= ~0xC;
+ for(;perso->roomNum != 0xFFFF;perso++)
+ {
+ if (perso->flags & PersonFlags::pf80)
+ continue;
+ if(perso->roomNum != p_global->roomNum)
+ continue;
+ persoType = perso->flags & PersonFlags::pfTypeMask;
+ if (persoType == PersonFlags::pftVelociraptor)
+ delinfo(p_global->cita_area_num + ValleyNews::vnVelociraptorsIn);
+ if (persoType == PersonFlags::pftTriceraptor)
+ delinfo(p_global->cita_area_num + ValleyNews::vnTriceraptorsIn);
+ perso->flags |= PersonFlags::pf20;
+ tab = tab_2CF70;
+ if(p_global->areaNum != Areas::arUluru && p_global->areaNum != Areas::arTamara)
+ tab = tab_2CEF0;
+ r27 = (room->flags & 0xC0) >> 2; //TODO: check me (like pc)
+ persoType = perso->flags & PersonFlags::pfTypeMask;
+ if (persoType == PersonFlags::pftTyrann)
+ persoType = 13;
+ r27 |= (persoType & 7) << 1; //TODO: check me 13 & 7 = ???
+ tab += r27;
+ p_global->roomVidNum = *tab++;
+ bank = *tab;
+ if(bank & 0x8000)
+ {
+ bank &= ~0x8000;
+ room->flags |= RoomFlags::rf08;
+ }
+ room->flags |= RoomFlags::rf04 | RoomFlags::rf02;
+ p_global->roomImgBank = bank;
+ break;
+ }
+}
+room_t* getsalle(short loc) //TODO: unsigned char?
+{
+ debug("get room for %X, starting from %d, looking for %X", loc, p_global->area_ptr->firstRoomIndex, p_global->partyOutside);
+ room_t *room = &gameRooms[p_global->area_ptr->firstRoomIndex];
+ loc &= 0xFF;
+ for(;;room++)
+ {
+ for(;room->location != loc;room++)
+ {
+ if(room->ff_0 == 0xFF)
+ return 0;
+ }
+ if(p_global->partyOutside == room->party || room->party == 0xFFFF)
+ break;
+ }
+ debug("found room: party = %X, bank = %X", room->party, room->bank);
+ p_global->roomImgBank = room->bank;
+ p_global->labyrinthRoom = 0;
+ if(p_global->roomImgBank > 104 && p_global->roomImgBank <= 112)
+ p_global->labyrinthRoom = p_global->roomImgBank - 103;
+ if(p_global->valleyVidNum)
+ p_global->roomVidNum = p_global->valleyVidNum;
+ else
+ p_global->roomVidNum = room->video;
+ if((room->flags & 0xC0) == RoomFlags::rf40 || (room->flags & RoomFlags::rf01))
+ getdino(room);
+ if(room->flags & RoomFlags::rfHasCitadel)
+ {
+ delinfo(p_global->areaNum + ValleyNews::vnCitadelLost);
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannIn);
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannLost);
+ delinfo(p_global->areaNum + ValleyNews::vnVelociraptorsLost);
+ }
+ if(istyran(p_global->roomNum))
+ p_global->gameFlags |= GameFlags::gfFlag10;
+ else
+ p_global->gameFlags &= ~GameFlags::gfFlag10;
+ return room;
+}
+void initlieu(short roomNum)
+{
+ area_t *area;
+ p_global->gameFlags |= GameFlags::gfFlag4000;
+ gameIcons[18].cursor_id |= 0x8000;
+ p_global->last_area_ptr = p_global->area_ptr;
+ p_global->area_ptr = &kAreasTable[((roomNum >> 8) & 0xFF) - 1];
+ area = p_global->area_ptr;
+ area->visitCount++;
+ p_global->areaVisitCount = area->visitCount;
+ p_global->curAreaFlags = area->flags;
+ p_global->curAreaType = area->type;
+ p_global->curCitadelLevel = area->citadelLevel;
+ if(p_global->curAreaType == AreaType::atValley)
+ gameIcons[18].cursor_id &= ~0x8000;
+ loadsal(area->salNum);
+}
+void maj2()
+{
+ char r9, r30;
+ room_t *room = p_global->room_ptr; //TODO: unused
+ aflieu();
+ assert(ScreenView.pitch == 320);
+ if(p_global->roomNum == 273 && p_global->prevLocation == 18)
+ p_global->ff_102 = 1;
+ if(p_global->eventType == EventType::etEventC)
+ {
+ afftopscr();
+ showobjects();
+ }
+ FRDevents();
+ assert(ScreenView.pitch == 320);
+ r9 = 0;
+ if (p_global->curAreaType == AreaType::atValley && !(p_global->displayFlags & DisplayFlags::dfPanable))
+ r9 = 1;
+ r30 = r9; //TODO: ^^ inlined func?
+ if(p_global->ff_102 || p_global->ff_103)
+ afficher();
+ else if (p_global->ff_F1 == (RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01))
+ {
+ blackbars();
+ effet1();
+ }
+ else if(p_global->ff_F1 && !(p_global->ff_F1 & RoomFlags::rf04) && !r30)
+ {
+ if (!(p_global->displayFlags & DisplayFlags::dfPanable))
+ blackbars();
+ else if(p_global->valleyVidNum)
+ blackbars();
+ effet1();
+ }
+ else if(r30 && !(p_global->ff_F1 & RoomFlags::rf04))
+ effetpix();
+ else
+ afficher128();
+ musique();
+ if(p_global->eventType != EventType::etEventC)
+ {
+ afftopscr();
+ showobjects();
+ }
+ bars_in();
+ showevents();
+ p_global->labyrinthDirections = 0;
+ specialin();
+}
+void majsalle1(short roomNum)
+{
+ room_t *room = getsalle(roomNum & 0xFF);
+ p_global->room_ptr = room;
+ debug("DrawRoom: room 0x%X, arg = 0x%X", p_global->roomNum, roomNum);
+ p_global->curRoomFlags = room->flags;
+ p_global->ff_F1 = room->flags;
+ animpiece();
+ p_global->ff_100 = 0;
+ maj2();
+}
+void maj_salle(unsigned short roomNum)
+{
+ setpersohere();
+ majsalle1(roomNum);
+}
+void initbuf()
+{
+#define ALLOC(ptr, size, typ) if(!((ptr) = (typ*)malloc(size))) quit_flag = 1;
+ ALLOC(bigfile_header, 0x10000, pak_t);
+ ALLOC(gameRooms, 0x4000, room_t);
+ ALLOC(gameIcons, 0x4000, icon_t);
+ ALLOC(bank_data_buf, 0x10000, unsigned char);
+ ALLOC(p_global, sizeof(*p_global), global_t);
+ ALLOC(sal_buf, 2048, void);
+ ALLOC(gameConditions, 0x4800, unsigned char);
+ ALLOC(gameDialogs, 0x2800, unsigned char);
+ ALLOC(gamePhrases, 0x10000, unsigned char);
+ ALLOC(main_bank_buf, 0x9400, unsigned char);
+ ALLOC(glow_buffer, 0x2800, unsigned char);
+ ALLOC(gameFont, 0x900, unsigned char);
+ ALLOC(gameLipsync, 0x205C, unsigned char);
+ ALLOC(music_buf, 0x140000, unsigned char);
+#undef ALLOC
+}
+void freebuf()
+{
+ free(bigfile_header);
+ free(gameRooms);
+ free(gameIcons);
+ free(bank_data_buf);
+ free(p_global);
+ free(sal_buf);
+ free(gameConditions);
+ free(gameDialogs);
+ free(gamePhrases);
+ free(main_bank_buf);
+ free(glow_buffer);
+ free(gameFont);
+ free(gameLipsync);
+ free(music_buf);
+}
+void openwindow()
+{
+ p_underBarsView = CLView_New(320, 40);
+ p_underBarsView->norm.width = 320;
+
+ p_view2 = CLView_New(32, 32);
+ p_view2_buf = p_view2->p_buffer;
+
+ p_subtitlesview = CLView_New(subtitles_x_width, 60);
+ p_subtitlesview_buf = p_subtitlesview->p_buffer;
+
+ p_underSubtitlesView = CLView_New(subtitles_x_width, 60);
+ p_underSubtitlesView_buf = p_underSubtitlesView->p_buffer;
+
+ p_mainview = CLView_New(640, 200);
+ p_mainview->norm.width = 320;
+ CLBlitter_FillView(p_mainview, 0xFFFFFFFF);
+ CLView_SetSrcZoomValues(p_mainview, 0, 0);
+ CLView_SetDisplayZoomValues(p_mainview, 640, 400);
+ CLScreenView_CenterIn(p_mainview);
+ p_mainview_buf = p_mainview->p_buffer;
+
+ mouse_x_center = p_mainview->norm.dst_left + p_mainview->norm.width / 2;
+ mouse_y_center = p_mainview->norm.dst_top + p_mainview->norm.height / 2;
+ CLMouse_SetPosition(mouse_x_center, mouse_y_center);
+ CLMouse_Hide();
+
+ curs_x = 320 / 2;
+ curs_y = 200 / 2;
+}
+void EmergencyExit()
+{
+ SysBeep(1);
+}
+public:
+void main()
+{
+ debug("global size is %X", (size_t)(&((global_t*)0)->save_end));
+ if ((size_t)(&((global_t*)0)->__UNUSED_70) != 0x70) // let's be more optimistic
+ {
+ // great, you broke the dialog system. expect all nasty stuff now
+ assert(0);
+ }
+
+
+
+ CRYOLib_Init();
+ CRYOLib_InstallExitPatch();
+ CRYOLib_SetDebugMode(0);
+ word_378CE = 0;
+ CRYOLib_MinimalInit();
+ CRYOLib_TestConfig();
+ CRYOLib_ManagersInit();
+ CLFile_SetFilter(1, 'EDNS', 0, 0, 0);
+// CRYOLib_InstallEmergencyExit(EmergencyExit);
+ CRYOLib_SetupEnvironment();
+ CLHNM_SetupSound(5, 0x2000, 8, 11025 * 65536.0 , 0);
+ CLHNM_SetForceZero2Black(1);
+ CLHNM_SetupTimer(12.5);
+ voiceSound = CLSoundRaw_New(0, 11025 * 65536.0, 8, 0);
+ hnmsound_ch = CLHNM_GetSoundChannel();
+ music_channel = CLSoundChannel_New(0);
+ CLSound_SetWantsDesigned(1);
+
+ initbuf();
+ openbigfile();
+ openwindow();
+ loadpermfiles();
+
+ if(!quit_flag)
+ {
+ LostEdenMac_InitPrefs();
+ init_cube();
+ p_mainview->doubled = doubled;
+ while(!quit_flag2)
+ {
+ init_globals();
+ quit_flag3 = 0;
+ normalCursor = 1;
+ torchCursor = 0;
+ curs_keepy = -1;
+ curs_keepx = -1;
+ CLDesktop_TestOpenFileAtStartup();
+ if(!gameLoaded)
+ intro();
+ edmain();
+ if(quit_flag)
+ goto quit;
+ startmusique(1);
+ blackbars();
+ afficher();
+ fadetoblack(3);
+ ClearScreen();
+ playhnm(95);
+ if(p_global->endGameFlag == 50)
+ {
+ loadrestart();
+ gameLoaded = 0;
+ }
+ fademusica0(2);
+ CLSoundChannel_Stop(music_channel);
+ CLSoundGroup_Free(mus_queue_grp);
+ musicPlaying = 0;
+ mus_queue_grp = 0;
+ }
+// LostEdenMac_SavePrefs();
+ }
+quit:;
+ fadetoblack(4);
+ closebigfile();
+ freebuf();
+ CRYOLib_RestoreEnvironment();
+ CRYOLib_ManagersDone();
+ CRYOLib_Done();
+ CRYOLib_RemoveExitPatch();
+}
+private:
+void edmain()
+{
+ //TODO
+ entergame();
+ while(!quit_flag && !quit_flag3 && p_global->endGameFlag != 50)
+ {
+ if(!gameStarted)
+ {
+ // if in demo mode, reset game after a while
+ demoCurrentTicks = TimerTicks;
+ if(demoCurrentTicks - demoStartTicks > 3000)
+ {
+ rundcurs();
+ afficher();
+ fademusica0(2);
+ fadetoblack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(p_mainview, 0);
+ CLSoundChannel_Stop(music_channel);
+ CLSoundGroup_Free(mus_queue_grp);
+ musicPlaying = 0;
+ mus_queue_grp = 0;
+ intro();
+ entergame();
+ }
+ }
+ rundcurs();
+ musicspy();
+ FRDevents();
+ narrateur();
+ evenchrono();
+ if ( p_global->drawFlags & DrawFlags::drDrawInventory) showobjects();
+ if ( p_global->drawFlags & DrawFlags::drDrawTopScreen) afftopscr();
+ if ((p_global->displayFlags & DisplayFlags::dfPanable) && (p_global->displayFlags != DisplayFlags::dfPerson)) scrollpano();
+ if ((p_global->displayFlags & DisplayFlags::dfMirror) && (p_global->displayFlags != DisplayFlags::dfPerson)) scrollmiroir();
+ if ((p_global->displayFlags & DisplayFlags::dfFresques) && (p_global->displayFlags != DisplayFlags::dfPerson)) scrollfresques();
+ if ( p_global->displayFlags & DisplayFlags::dfFlag2) noclicpanel();
+ if (animationActive) anim_perso();
+ update_cursor();
+ afficher();
+ }
+}
+void intro()
+{
+#if 0
+ return;
+#endif
+
+ short speed = 0;
+ if(!machine_speed)
+ {
+ if(!word_378CC)
+ speed = 4;
+ else
+ {
+ if(CLComputer_Has68030())
+ speed = 1;
+ if(CLComputer_Has68040())
+ speed = 2;
+ }
+ if(speed == 2)
+ if(testcdromspeed())
+ speed++;
+ machine_speed = speed;
+ }
+ if(machine_speed == 1)
+ {
+ doubled = 0;
+ p_mainview->doubled = doubled;
+ if(ScreenView.width < 640 || ScreenView.height < 400)
+ allow_doubled = 0;
+ }
+ if(machine_speed < 3)
+ playhnm(98);
+ else
+ {
+ CLSoundChannel_Stop(hnmsound_ch);
+ CLHNM_CloseSound();
+ CLHNM_SetupSound(5, 0x2000, 16, 22050 * 65536.0, 0);
+ hnmsound_ch = CLHNM_GetSoundChannel();
+ playhnm(2012);
+ }
+ playhnm(171);
+ CLBlitter_FillScreenView(0);
+ specialTextMode = 0;
+ if(machine_speed < 3)
+ playhnm(170);
+ else
+ {
+ playhnm(2001);
+ CLSoundChannel_Stop(hnmsound_ch);
+ CLHNM_CloseSound();
+ CLHNM_SetupSound(5, 0x2000, 8, 11025 * 65536.0, 0);
+ hnmsound_ch = CLHNM_GetSoundChannel();
+ }
+}
+char testcdromspeed()
+{
+ return 1;
+}
+void entergame()
+{
+ char flag = 0;
+ currentTime = TimerTicks / 100;
+ p_global->gameTime = currentTime;
+ demoStartTicks = TimerTicks;
+ gameStarted = 0;
+ if(!gameLoaded)
+ {
+ p_global->roomNum = 279;
+ p_global->areaNum = Areas::arMo;
+ p_global->ff_100 = -1;
+ initlieu(p_global->roomNum);
+ p_global->currentMusicNum = 0;
+ startmusique(1);
+ }
+ else
+ {
+ flag = p_global->autoDialog == 0xFF; //TODO
+ initafterload();
+ lastMusicNum = p_global->currentMusicNum; //TODO: ???
+ p_global->currentMusicNum = 0;
+ startmusique(lastMusicNum);
+ p_global->inventoryScrollPos = 0;
+ gameStarted = 1;
+ }
+ showobjects();
+ afftopscr();
+ sauvefrises();
+ showBlackBars = 1;
+ p_global->ff_102 = 1;
+ maj_salle(p_global->roomNum);
+ if(flag)
+ {
+ p_global->iconsIndex = 4;
+ p_global->autoDialog = -1;
+ parle_moi();
+ }
+}
+void signon(char *s)
+{
+}
+void testPommeQ()
+{
+ char key;
+ if(!CLKeyboard_HasCmdDown())
+ return;
+ key = CLKeyboard_GetLastASCII();
+ if(key == 'Q' || key == 'q')
+ if(!pomme_q)
+ pomme_q = 1;
+}
+void FRDevents()
+{
+ short dx, dy, max_y;
+ CLKeyboard_Read();
+ if(allow_doubled)
+ {
+ if(CLKeyboard_IsScanCodeDown(0x30)) //TODO: const
+ {
+ if(!keybd_held)
+ {
+ doubled = !doubled;
+ p_mainview->doubled = doubled;
+ CLBlitter_FillScreenView(0);
+ keybd_held = 1;
+ }
+ }
+ else
+ keybd_held = 0;
+ }
+ CLMouse_GetPosition(&mouse_x, &mouse_y);
+ dx = mouse_x - mouse_x_center;
+ dy = mouse_y - mouse_y_center;
+ CLMouse_SetPosition(mouse_x_center, mouse_y_center);
+ curs_x += dx;
+ if(curs_x < 4)
+ curs_x = 4;
+ if(curs_x > 292)
+ curs_x = 292;
+ curs_y += dy;
+ max_y = p_global->displayFlags == DisplayFlags::dfFlag2 ? 190 : 170;
+ if(curs_y < 4)
+ curs_y = 4;
+ if(curs_y > max_y)
+ curs_y = max_y;
+ curs_x_pan = curs_x;
+ if(curs_y >= 10 && curs_y <= 164 && !(p_global->displayFlags & DisplayFlags::dfFresques))
+ curs_x_pan += scroll_pos;
+ if(normalCursor)
+ {
+ current_cursor = 0;
+ current_spot = scan_icon_list(curs_x_pan + curs_center, curs_y + curs_center, p_global->iconsIndex);
+ if(current_spot)
+ current_cursor = current_spot->cursor_id;
+ }
+ if(curs_center == 0 && current_cursor != 53)
+ {
+ curs_center = 11;
+ curs_x -= 11;
+ }
+ if(curs_center == 11 && current_cursor == 53)
+ {
+ curs_center = 0;
+ curs_x += 11;
+ }
+ if(p_global->displayFlags & DisplayFlags::dfPanable)
+ {
+ //TODO: current_spot may be zero (due to scan_icon_list failure) if cursor slips between hot areas.
+ //fix me here or above?
+ if (current_spot) // ok, plug it here
+ {
+ current_spot2 = current_spot;
+ affrepereadam(current_spot2->action_id - 14);
+ }
+ }
+ if(p_global->displayFlags == DisplayFlags::dfFlag2 && current_spot)
+ current_spot2 = current_spot;
+ if(p_global->displayFlags & DisplayFlags::dfFresques)
+ {
+ if(fresqTalk)
+ restaurefondbulle();
+ if(current_cursor == 9 && !torchCursor)
+ {
+ rundcurs();
+ torchCursor = 1;
+ glow_x = -1;
+ }
+ if(current_cursor != 9 && torchCursor == 1)
+ {
+ unglow();
+ torchCursor = 0;
+ curs_saved = 0;
+ }
+ }
+ if(CLMouse_IsDown())
+ {
+ if(!mouse_held)
+ {
+ mouse_held = 1;
+ gameStarted = 1;
+ mouse();
+ }
+ }
+ else
+ mouse_held = 0;
+ if(p_global->displayFlags != DisplayFlags::dfFlag2)
+ {
+ if(--inventoryScrollDelay <= 0)
+ {
+ if(p_global->obj_count > 9 && curs_y > 164)
+ {
+ if(curs_x > 284 && p_global->inventoryScrollPos + 9 < p_global->obj_count)
+ {
+ p_global->inventoryScrollPos++;
+ inventoryScrollDelay = 20;
+ showobjects();
+ }
+ if(curs_x < 30 && p_global->inventoryScrollPos != 0)
+ {
+ p_global->inventoryScrollPos--;
+ inventoryScrollDelay = 20;
+ showobjects();
+ }
+ }
+ }
+ }
+ if(inventoryScrollDelay < 0)
+ inventoryScrollDelay = 0;
+ if(!pomme_q)
+ {
+ testPommeQ();
+ if(pomme_q)
+ {
+ PommeQ();
+ return; //TODO: useless
+ }
+ }
+}
+icon_t* scan_icon_list(short x, short y, short index)
+{
+ icon_t* icon;
+ for(icon = &gameIcons[index];icon->sx >= 0;icon++)
+ {
+ if (icon->cursor_id & 0x8000)
+ continue;
+#if 0
+ // MAC version use this check. Same check is present in PC version, but never used
+ // Because of x >= clause two adjacent rooms has 1-pixel wide dead zone between them
+ // On valley view screens if cursor slips in this zone a crash in FRDevents occurs
+ // due to lack of proper checks
+ if(x < icon->ff_0 || x >= icon->ff_4
+ || y < icon->ff_2 || y >= icon->ff_6)
+#else
+ // PC version has this check inlined in FRDevents
+ // Should we keep it or fix edge coordinates in afroom() instead?
+ if (x < icon->sx || x > icon->ex
+ || y < icon->sy || y > icon->ey)
+#endif
+ continue;
+ return icon;
+ }
+ return 0;
+}
+void update_cursor()
+{
+ if(++word_2C300 > 3)
+ word_2C300 = 0;
+ if(!word_2C300)
+ {
+ word_2C304++;
+ word_2C302++;
+ }
+ if(word_2C304 > 8)
+ word_2C304 = 0;
+ if(word_2C302 > 4)
+ word_2C302 = 0;
+ if(!torchCursor)
+ {
+ use_main_bank();
+ sundcurs(curs_x + scroll_pos, curs_y);
+ if(current_cursor != 53 && current_cursor < 10) //TODO: cond
+ moteur();
+ else
+ noclipax(current_cursor, curs_x + scroll_pos, curs_y);
+ glow_x = 1;
+ }
+ else
+ {
+ use_bank(117);
+ if(curs_x > 294)
+ curs_x = 294;
+ unglow();
+ glow(word_2C302);
+ noclipax(word_2C304, curs_x + scroll_pos, curs_y);
+ if(fresqTalk)
+ af_subtitle();
+ }
+}
+void mouse()
+{
+ static void (EdenGameImpl::*mouse_actions[])() = {
+ &EdenGameImpl::goto_nord,
+ &EdenGameImpl::goto_est,
+ &EdenGameImpl::goto_sud,
+ &EdenGameImpl::goto_ouest,
+ &EdenGameImpl::plaquemonk,
+ &EdenGameImpl::fresquesgraa,
+ &EdenGameImpl::pushpierre,
+ &EdenGameImpl::tetesquel,
+ &EdenGameImpl::tetemomie,
+ &EdenGameImpl::goto_nord,
+ &EdenGameImpl::roiparle1,
+ &EdenGameImpl::roiparle2,
+ &EdenGameImpl::roiparle3,
+ &EdenGameImpl::gotohall,
+ &EdenGameImpl::demitourlabi,
+ &EdenGameImpl::squelmoorkong,
+ &EdenGameImpl::gotonido,
+ &EdenGameImpl::voirlac,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::final,
+ &EdenGameImpl::goto_nord,
+ &EdenGameImpl::goto_sud,
+ &EdenGameImpl::visiter,
+ &EdenGameImpl::dinosoufle,
+ &EdenGameImpl::fresqueslasc,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ &EdenGameImpl::gotoval,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::getprisme,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::getoeuf,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::getchampb,
+ &EdenGameImpl::getchampm,
+ &EdenGameImpl::getcouteau,
+ &EdenGameImpl::getnidv,
+ &EdenGameImpl::getnido,
+ &EdenGameImpl::getor,
+ nullptr,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::getsoleil,
+ &EdenGameImpl::getcorne,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::ret,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::getplaque,
+ &EdenGameImpl::clicplanval,
+ &EdenGameImpl::finfresques,
+ &EdenGameImpl::choisir,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::roi,
+ &EdenGameImpl::dina,
+ &EdenGameImpl::thoo,
+ &EdenGameImpl::monk,
+ &EdenGameImpl::bourreau,
+ &EdenGameImpl::messager,
+ &EdenGameImpl::mango,
+ &EdenGameImpl::eve,
+ &EdenGameImpl::azia,
+ &EdenGameImpl::mammi,
+ &EdenGameImpl::gardes,
+ &EdenGameImpl::fisher,
+ &EdenGameImpl::dino,
+ &EdenGameImpl::tyran,
+ &EdenGameImpl::morkus,
+ &EdenGameImpl::ret,
+ &EdenGameImpl::parle_moi,
+ &EdenGameImpl::adam,
+ &EdenGameImpl::takeobject,
+ &EdenGameImpl::putobject,
+ &EdenGameImpl::clictimbre,
+ &EdenGameImpl::dinaparle,
+ &EdenGameImpl::close_perso,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGameImpl::generique,
+ &EdenGameImpl::choixsubtitle,
+ &EdenGameImpl::EdenQuit,
+ &EdenGameImpl::restart,
+ &EdenGameImpl::cancel2,
+ &EdenGameImpl::testvoice,
+ &EdenGameImpl::reglervol,
+ &EdenGameImpl::load,
+ &EdenGameImpl::save,
+ &EdenGameImpl::cliccurstape,
+ &EdenGameImpl::playtape,
+ &EdenGameImpl::stoptape,
+ &EdenGameImpl::rewindtape,
+ &EdenGameImpl::forwardtape,
+ &EdenGameImpl::confirmyes,
+ &EdenGameImpl::confirmno,
+ &EdenGameImpl::gotocarte
+ };
+
+ if(!(current_spot = scan_icon_list(curs_x_pan + curs_center,
+ curs_y + curs_center, p_global->iconsIndex)))
+ return;
+ current_spot2 = current_spot;
+ debug("invoking mouse action %d", current_spot->action_id);
+ if(mouse_actions[current_spot->action_id])
+ (this->*mouse_actions[current_spot->action_id])();
+}
+////// film.c
+void showfilm(char arg1)
+{
+ short playing;
+ CLHNM_Prepare2Read(p_hnmcontext, 0);
+ CLHNM_ReadHeader(p_hnmcontext);
+ if(p_global->curVideoNum == 92)
+ {
+ p_hnmcontext->header.flag2 = 0;
+ CLSoundChannel_SetVolumeLeft(hnmsound_ch, 0);
+ CLSoundChannel_SetVolumeRight(hnmsound_ch, 0);
+ }
+ playing = 1;
+ if(CLHNM_GetVersion(p_hnmcontext) != 4)
+ return;
+ CLHNM_AllocMemory(p_hnmcontext);
+ p_hnmview = CLView_New(p_hnmcontext->header.width, p_hnmcontext->header.height);
+ CLView_SetSrcZoomValues(p_hnmview, 0, 0);
+ CLView_SetDisplayZoomValues(p_hnmview, p_hnmcontext->header.width * 2, p_hnmcontext->header.height * 2);
+ CLScreenView_CenterIn(p_hnmview);
+ p_hnmview_buf = p_hnmview->p_buffer;
+ if(arg1)
+ {
+ p_hnmview->norm.height = 160;
+ p_hnmview->zoom.height = 320; //TODO: width??
+ p_hnmview->norm.dst_top = p_mainview->norm.dst_top + 16;
+ p_hnmview->zoom.dst_top = p_mainview->zoom.dst_top + 32;
+ }
+ CLHNM_SetFinalBuffer(p_hnmcontext, p_hnmview->p_buffer);
+ p_hnmview->doubled = doubled;
+ do
+ {
+ hnm_position = CLHNM_GetFrameNum(p_hnmcontext);
+ CLHNM_WaitLoop(p_hnmcontext);
+ playing = CLHNM_NextElement(p_hnmcontext);
+ if(specialTextMode)
+ bullehnm();
+ else
+ musicspy();
+ CLBlitter_CopyView2Screen(p_hnmview);
+ assert(ScreenView.pitch == 320);
+ CLKeyboard_Read();
+ if(allow_doubled)
+ {
+ if(CLKeyboard_IsScanCodeDown(0x30)) //TODO: const
+ {
+ if(!keybd_held)
+ {
+ doubled = !doubled;
+ p_hnmview->doubled = doubled; //TODO: but mainview ?
+ CLBlitter_FillScreenView(0);
+ keybd_held = 1;
+ }
+ }
+ else
+ keybd_held = 0;
+ }
+ if(arg1)
+ {
+ if(CLMouse_IsDown())
+ {
+ if(!mouse_held)
+ {
+ mouse_held = 1;
+ videoCanceled = 1;
+ }
+ }
+ else
+ mouse_held = 0;
+ }
+ }
+ while(playing && !videoCanceled);
+ CLView_Free(p_hnmview);
+ CLHNM_DeallocMemory(p_hnmcontext);
+}
+void playhnm(short num)
+{
+ perso_t *perso;
+ short oldDialogType;
+ p_global->curVideoNum = num;
+ if(num != 2001 && num != 2012 && num != 98 && num != 171)
+ {
+ unsigned char oldMusicType = p_global->newMusicType;
+ p_global->newMusicType = MusicType::mtEvent;
+ musique();
+ musicspy();
+ p_global->newMusicType = oldMusicType;
+ }
+ p_global->videoSubtitleIndex = 1;
+ if(specialTextMode)
+ {
+ perso = p_global->perso_ptr;
+ oldDialogType = p_global->dialogType;
+ prechargephrases(num);
+ fademusica0(1);
+ CLSoundChannel_Stop(music_channel);
+ }
+ showVideoSubtitle = 0;
+ videoCanceled = 0;
+ shnmfl(num);
+ CLHNM_Reset(p_hnmcontext);
+ CLHNM_FlushPreloadBuffer(p_hnmcontext);
+ if(needToFade)
+ {
+ fadetoblack(4);
+ ClearScreen();
+ needToFade = 0;
+ }
+ if(num == 2012 || num == 98 || num == 171)
+ showfilm(0);
+ else
+ showfilm(1);
+ curs_keepx = curs_keepy = -1;
+ p_mainview->doubled = doubled;
+ if(specialTextMode)
+ {
+ mus_fade_flags = 3;
+ musicspy();
+ p_global->perso_ptr = perso;
+ p_global->dialogType = oldDialogType;
+ specialTextMode = 0;
+ }
+ if(videoCanceled)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if(p_global->curVideoNum == 167)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if(p_global->curVideoNum == 104)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if(p_global->curVideoNum == 102)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if(p_global->curVideoNum == 77)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if(p_global->curVideoNum == 149)
+ p_global->ff_F1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+}
+void bullehnm()
+{
+ short *frames, *frames_start, frame, num;
+ perso_t *perso;
+ switch(p_global->curVideoNum)
+ {
+ case 170:
+ frames = tab_2D24C;
+ perso = &kPersons[PER_UNKN_156];
+ break;
+ case 83:
+ frames = tab_2D28E;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 88:
+ frames = tab_2D298;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 89:
+ frames = tab_2D2AA;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 94:
+ frames = tab_2D2C4;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ default:
+ return;
+ }
+ frames_start = frames;
+ while((frame = *frames++) != -1)
+ {
+ if((frame & ~0x8000) == hnm_position)
+ break;
+ }
+ if(frame == -1)
+ {
+ if(showVideoSubtitle)
+ af_subtitlehnm();
+ return;
+ }
+ if(frame & 0x8000)
+ showVideoSubtitle = 0;
+ else
+ {
+ p_global->videoSubtitleIndex = (frames - frames_start) / 2 + 1;
+ p_global->perso_ptr = perso;
+ p_global->dialogType = DialogType::dtInspect;
+ num = (perso->id << 3) | p_global->dialogType;
+ dialoscansvmas((dial_t*)GetElem(gameDialogs, num));
+ showVideoSubtitle = 1;
+ }
+ if(showVideoSubtitle)
+ af_subtitlehnm();
+}
+////// sound.c
+void musique()
+{
+ unsigned char flag, hidx, lidx, mus;
+ dial_t *dial;
+ if(p_global->newMusicType == MusicType::mtDontChange)
+ return;
+ dial = (dial_t*)GetElem(gameDialogs, 128);
+ for(;;dial++)
+ {
+ if (dial->flags == -1 && dial->condNumLow == -1)
+ return;
+ flag = dial->flags;
+ hidx = (dial->textCondHiMask & 0xC0) >> 6;
+ lidx = dial->condNumLow; //TODO: fixme - unsigned = signed
+ if(flag & 0x10)
+ hidx |= 4;
+ if(testcondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ }
+ mus = dial->textNumLow;
+ p_global->newMusicType = MusicType::mtDontChange;
+ if(mus != 0 && mus != 2 && mus < 50)
+ startmusique(mus);
+}
+void startmusique(unsigned char num)
+{
+ short seq_size, pat_size, freq;
+ if (num == p_global->currentMusicNum)
+ return;
+ if(musicPlaying)
+ {
+ fademusica0(1);
+ CLSoundChannel_Stop(music_channel);
+ CLSoundGroup_Free(mus_queue_grp);
+ }
+ loadmusicfile(num);
+ p_global->currentMusicNum = num;
+ mus_sequence_ptr = music_buf + 32; //TODO: rewrite it properly
+ seq_size = PLE16(music_buf + 30);
+ mus_patterns_ptr = music_buf + 30 + seq_size;
+ pat_size = PLE16(music_buf + 27);
+ mus_samples_ptr = music_buf + 32 + 4 + pat_size;
+ freq = PLE16(mus_samples_ptr - 2);
+ if(freq == 166)
+ mus_queue_grp = CLSoundGroup_New(3, 0, 8, 7.225344e8, 0);
+ else
+ mus_queue_grp = CLSoundGroup_New(3, 0, 8, 1.4450688e9, 0);
+ musicSequencePos = 0;
+ mus_vol_left = p_global->pref_10C[0];
+ mus_vol_right = p_global->pref_10C[1];
+ CLSoundChannel_SetVolumeLeft(music_channel, mus_vol_left);
+ CLSoundChannel_SetVolumeRight(music_channel, mus_vol_right);
+}
+void musicspy()
+{
+ unsigned char patnum, *patptr;
+ int ofs, len;
+ if(!mus_queue_grp)
+ return;
+ mus_vol_left = p_global->pref_10C[0];
+ mus_vol_right = p_global->pref_10C[1];
+ if(mus_fade_flags & 3)
+ fademusicup();
+ if(personTalking && !hnmsound_ch->numSounds)
+ mus_fade_flags = 3;
+ if(music_channel->numSounds < 3)
+ {
+ patnum = mus_sequence_ptr[musicSequencePos];
+ if(patnum == 0xFF)
+ {
+ // rewind
+ musicSequencePos = 0;
+ patnum = mus_sequence_ptr[musicSequencePos];
+ }
+ musicSequencePos++;
+ patptr = mus_patterns_ptr + patnum * 6;
+ ofs = patptr[0] + (patptr[1] << 8) + (patptr[2] << 16);
+ len = patptr[3] + (patptr[4] << 8) + (patptr[5] << 16);
+ CLSoundGroup_AssignDatas(mus_queue_grp, mus_samples_ptr + ofs, len, 0);
+ CLSoundGroup_PlayNextSample(mus_queue_grp, music_channel);
+ musicPlaying = 1;
+ }
+}
+int loadmusicfile(short num)
+{
+ short res;
+ long numread;
+ pakfile_t *file = &bigfile_header->files[num + 435];
+ long size = PLE32(&file->size);
+ long offs = PLE32(&file->offs);
+ CLFile_SetPosition(h_bigfile, 1, offs);
+ numread = size;
+ if(numread > 0x140000) //TODO: const
+ numread = 0x140000;
+ CLFile_Read(h_bigfile, music_buf, &numread);
+ return size;
+}
+void persovox()
+{
+ short vol_l, vol_r, step_l, step_r;
+ short num = p_global->textNum;
+ if(p_global->textBankIndex != 1)
+ num += 565;
+ if(p_global->textBankIndex == 3)
+ num += 707;
+ voiceSamplesSize = ssndfl(num);
+ vol_l = p_global->pref_110[0];
+ vol_r = p_global->pref_110[1];
+ step_l = -1;
+ if(music_channel->volumeLeft < vol_l)
+ step_l = 1;
+ step_r = -1;
+ if(music_channel->volumeRight < vol_r)
+ step_r = 1;
+ do
+ {
+ if(vol_l != music_channel->volumeLeft)
+ CLSoundChannel_SetVolumeLeft(music_channel, music_channel->volumeLeft + step_l);
+ if(vol_r != music_channel->volumeRight)
+ CLSoundChannel_SetVolumeRight(music_channel, music_channel->volumeRight + step_r);
+ }
+ while(music_channel->volumeLeft != vol_l || music_channel->volumeRight != vol_r);
+ vol_l = p_global->pref_10E[0];
+ vol_r = p_global->pref_10E[1];
+ CLSoundChannel_SetVolumeLeft(hnmsound_ch, vol_l);
+ CLSoundChannel_SetVolumeRight(hnmsound_ch, vol_r);
+ CLSound_SetWantsDesigned(0);
+ CLSoundRaw_AssignBuffer(voiceSound, voiceSamplesBuffer, 0, voiceSamplesSize);
+ CLSoundChannel_Play(hnmsound_ch, voiceSound);
+ personTalking = 1;
+ mus_fade_flags = 0;
+ last_anim_ticks = TimerTicks;
+}
+void endpersovox()
+{
+ restaurefondbulle();
+ if(personTalking)
+ {
+ CLSoundChannel_Stop(hnmsound_ch);
+ personTalking = 0;
+ mus_fade_flags = 3;
+ }
+ if(soundAllocated)
+ {
+ CLMemory_Free(voiceSamplesBuffer);
+ soundAllocated = 0;
+ }
+}
+void fademusicup()
+{
+ short vol;
+ if(mus_fade_flags & 2)
+ {
+ vol = music_channel->volumeLeft;
+ if(vol < mus_vol_left)
+ {
+ vol += 8;
+ if(vol > mus_vol_left)
+ vol = mus_vol_left;
+ }
+ else
+ {
+ vol -= 8;
+ if(vol < mus_vol_left)
+ vol = mus_vol_left;
+ }
+ CLSoundChannel_SetVolumeLeft(music_channel, vol);
+ if(vol == mus_vol_left)
+ mus_fade_flags &= ~2;
+ }
+ if(mus_fade_flags & 1)
+ {
+ vol = music_channel->volumeRight;
+ if(vol < mus_vol_right)
+ {
+ vol += 8;
+ if(vol > mus_vol_right)
+ vol = mus_vol_right;
+ }
+ else
+ {
+ vol -= 8;
+ if(vol < mus_vol_right)
+ vol = mus_vol_right;
+ }
+ CLSoundChannel_SetVolumeRight(music_channel, vol);
+ if(vol == mus_vol_right)
+ mus_fade_flags &= ~1;
+ }
+}
+void fademusica0(short delay)
+{
+ short volume;
+ while((volume = CLSoundChannel_GetVolume(music_channel)) > 2)
+ {
+ volume -= 2;
+ if(volume < 2)
+ volume = 2;
+ CLSoundChannel_SetVolume(music_channel, volume);
+ wait(delay);
+ }
+}
+//// obj.c
+object_t* getobjaddr(short id)
+{
+ int i;
+ for(i = 0;i < MAX_OBJECTS;i++)
+ if(objects[i].id == id)
+ break;
+ return objects + i;
+}
+void countobjects()
+{
+ short index = 0;
+ unsigned char total = 0;
+ int i;
+ for(i = 0;i < MAX_OBJECTS;i++)
+ {
+ short count = objects[i].count;
+#ifdef EDEN_DEBUG
+count = 1;
+goto show_all_objects; //DEBUG
+#endif
+ if(count == 0)
+ continue;
+ if (objects[i].flags & ObjectFlags::ofInHands)
+ count--;
+show_all_objects:;
+ if(count)
+ {
+ total += count;
+ while(count--)
+ own_objects[index++] = objects[i].id;
+ }
+ }
+ p_global->obj_count = total;
+}
+void showobjects()
+{
+ short i, total, index;
+ icon_t *icon = &gameIcons[19];
+ p_global->drawFlags &= ~(DrawFlags::drDrawInventory | DrawFlags::drDrawFlag2);
+ countobjects();
+ total = p_global->obj_count;
+ for(i = 9;i--;icon++)
+ {
+ if(total)
+ {
+ icon->cursor_id &= ~0x8000;
+ total--;
+ }
+ else
+ icon->cursor_id |= 0x8000;
+ }
+ use_main_bank();
+ noclipax(55, 0, 176);
+ icon = &gameIcons[19];
+ total = p_global->obj_count;
+ index = p_global->inventoryScrollPos;
+ for(i = 9;total-- && i--;icon++)
+ {
+ char obj = own_objects[index++];
+ icon->object_id = obj;
+ noclipax(obj + 9, icon->sx, 178);
+ }
+ needPaletteUpdate = 1;
+ if((p_global->displayFlags & DisplayFlags::dfMirror) || (p_global->displayFlags & DisplayFlags::dfPanable))
+ {
+ sauvefrisesbas();
+ scroll();
+ }
+}
+void winobject(short id)
+{
+ object_t *object = getobjaddr(id);
+ object->flags |= ObjectFlags::ofFlag1;
+ object->count++;
+ p_global->curItemsMask |= object->itemMask;
+ p_global->wonItemsMask |= object->itemMask;
+ p_global->curPowersMask |= object->powerMask;
+ p_global->wonPowersMask |= object->powerMask;
+}
+void loseobject(short id)
+{
+ object_t *object = getobjaddr(id);
+ if(object->count > 0)
+ object->count--;
+ if(!object->count)
+ {
+ object->flags &= ~ObjectFlags::ofFlag1;
+ p_global->curItemsMask &= ~object->itemMask;
+ p_global->curPowersMask &= ~object->powerMask;
+ }
+ p_global->curObjectId = 0;
+ p_global->curObjectFlags = 0;
+ p_global->curObjectCursor = 9;
+ gameIcons[16].cursor_id |= 0x8000;
+ object->flags &= ~ObjectFlags::ofInHands;
+ normalCursor = 1;
+ current_cursor = 0;
+ torchCursor = 0;
+}
+void lostobject()
+{
+ byte_30AFE = 1;
+ if(p_global->curObjectId)
+ loseobject(p_global->curObjectId);
+}
+char objecthere(short id)
+{
+ object_t *object = getobjaddr(id);
+ for (pCurrentObjectLocation = &kObjectLocations[object->locations]; *pCurrentObjectLocation != -1; pCurrentObjectLocation++)
+ {
+ if(*pCurrentObjectLocation == p_global->roomNum)
+ return 1;
+ }
+ return 0;
+}
+void objectmain(short id)
+{
+ object_t *object = getobjaddr(id);
+ gameIcons[16].cursor_id &= ~0x8000;
+ p_global->curObjectId = object->id;
+ p_global->curObjectCursor = p_global->curObjectId + 9;
+ object->flags |= ObjectFlags::ofInHands;
+ p_global->curObjectFlags = object->flags;
+ current_cursor = p_global->curObjectId + 9;
+ normalCursor = 0;
+}
+void getobject(short id)
+{
+ room_t *room = p_global->room_ptr;
+ if(p_global->curObjectId)
+ return;
+ if(!objecthere(id))
+ return;
+ *pCurrentObjectLocation |= 0x8000;
+ objectmain(id);
+ winobject(id);
+ showobjects();
+ p_global->roomImgBank = room->bank;
+ p_global->roomVidNum = room->video;
+ aflieu();
+}
+void putobject()
+{
+ object_t *object;
+ if(!p_global->curObjectId)
+ return;
+ gameIcons[16].cursor_id |= 0x8000;
+ object = getobjaddr(p_global->curObjectId);
+ p_global->curObjectCursor = 9;
+ p_global->curObjectId = 0;
+ p_global->curObjectFlags = 0;
+ object->flags &= ~ObjectFlags::ofInHands;
+ p_global->next_dialog_ptr = 0;
+ byte_30B00 = 0;
+ p_global->dialogType = DialogType::dtTalk;
+ showobjects();
+ normalCursor = 1;
+}
+void newobject(short id, short arg2)
+{
+ object_t *object = getobjaddr(id);
+ short e, *t = &kObjectLocations[object->locations];
+ while((e = *t) != -1)
+ {
+ e &= ~0x8000;
+ if((e >> 8) == arg2)
+ *t = e;
+ t++;
+ }
+}
+void giveobjectal(short id)
+{
+ if (id == Objects::obKnife)
+ kObjectLocations[2] = 0;
+ if (id == Objects::obApple)
+ p_global->stepsToFindAppleNormal = 0;
+ if (id >= Objects::obEyeInTheStorm && id < (Objects::obRiverThatWinds + 1) && p_global->roomPersoType == PersonFlags::pftVelociraptor)
+ { //TODO: fix that cond above
+ object_t *object = getobjaddr(id);
+ p_global->room_perso->powers &= ~object->powerMask;
+ }
+ winobject(id);
+}
+void giveobject()
+{
+ unsigned char id;
+ id = p_global->giveobj1;
+ if(id)
+ {
+ p_global->giveobj1 = 0;
+ giveobjectal(id);
+ }
+ id = p_global->giveobj2;
+ if(id)
+ {
+ p_global->giveobj2 = 0;
+ giveobjectal(id);
+ }
+ id = p_global->giveobj3;
+ if(id)
+ {
+ p_global->giveobj3 = 0;
+ giveobjectal(id);
+ }
+}
+void takeobject()
+{
+ objectmain(current_spot2->object_id);
+ p_global->next_dialog_ptr = 0;
+ byte_30B00 = 0;
+ p_global->dialogType = 0;
+ if(p_global->inventoryScrollPos)
+ p_global->inventoryScrollPos--;
+ showobjects();
+}
+////
+void newchampi()
+{
+ if (objects[Objects::obShroom - 1].count == 0)
+ {
+ newobject(Objects::obShroom, p_global->cita_area_num);
+ newobject(Objects::obBadShroom, p_global->cita_area_num);
+ }
+}
+void newnidv()
+{
+ short *ptr;
+ object_t *obj;
+ room_t *room = p_global->cita_area_firstRoom;
+ if (objects[Objects::obNest - 1].count)
+ return;
+ obj = getobjaddr(Objects::obNest);
+ for (ptr = kObjectLocations + obj->locations; *ptr != -1; ptr++)
+ {
+ if((*ptr & ~0x8000) >> 8 != p_global->cita_area_num)
+ continue;
+ *ptr &= ~0x8000;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(room->location == (*ptr & 0xFF))
+ {
+ room->bank = 279;
+ room->ff_0 = 9;
+ room++;
+ room->bank = 280;
+ return;
+ }
+ }
+ }
+}
+void newnido()
+{
+ short *ptr;
+ object_t *obj;
+ room_t *room = p_global->cita_area_firstRoom;
+ if (objects[Objects::obFullNest - 1].count)
+ return;
+ if (objects[Objects::obNest - 1].count)
+ return;
+ obj = getobjaddr(Objects::obFullNest);
+ for (ptr = kObjectLocations + obj->locations; *ptr != -1; ptr++)
+ {
+ if((*ptr & ~0x8000) >> 8 != p_global->cita_area_num)
+ continue;
+ *ptr &= ~0x8000;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(room->location == (*ptr & 0xFF))
+ {
+ room->bank = 277;
+ room->ff_0 = 9;
+ room++;
+ room->bank = 278;
+ return;
+ }
+ }
+ }
+}
+void newor()
+{
+ if (objects[Objects::obGold - 1].count == 0)
+ {
+ newobject(Objects::obGold, p_global->cita_area_num);
+ }
+}
+void gotopanel()
+{
+ if(pomme_q)
+ byte_31D64 = p_global->autoDialog == 0xFF; //TODO: check me
+ no_palette = 0;
+ p_global->iconsIndex = 85;
+ p_global->perso_ptr = 0;
+ p_global->drawFlags |= DrawFlags::drDrawMenu;
+ p_global->displayFlags = DisplayFlags::dfFlag2;
+ p_global->menuFlags = 0;
+ affpanel();
+ fadetoblack(3);
+ afftoppano();
+ CLBlitter_CopyView2Screen(p_mainview);
+ CLPalette_Send2Screen(global_palette, 0, 256);
+ curs_x = 320 / 2;
+ curs_y = 200 / 2;
+ CLMouse_SetPosition(mouse_x_center, mouse_y_center);
+}
+void noclicpanel()
+{
+ unsigned char num;
+ if(p_global->menuFlags & MenuFlags::mfFlag4)
+ {
+ depcurstape();
+ return;
+ }
+ if(p_global->drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ if(p_global->menuFlags & MenuFlags::mfFlag1)
+ {
+ changervol();
+ return;
+ }
+ if(current_spot2 >= &gameIcons[119])
+ {
+ debug("noclic: objid = %4X, glob3,2 = %2X %2X", current_spot2, p_global->menuItemIdHi, p_global->menuItemIdLo);
+ if(current_spot2->object_id == (p_global->menuItemIdLo + p_global->menuItemIdHi) << 8) //TODO: check me
+ return;
+ }
+ else
+ {
+ int idx = current_spot2 - &gameIcons[105];
+ if(idx == 0)
+ {
+ p_global->menuItemIdLo = 1;
+ num = 1;
+ goto skip;
+ }
+ num = idx & 0x7F + 1;
+ if(num >= 5)
+ num = 1;
+ if(num == p_global->ff_43)
+ return;
+ p_global->ff_43 = 0;
+ }
+ num = p_global->menuItemIdLo;
+ p_global->menuItemIdLo = current_spot2->object_id & 0xFF;
+skip:;
+ p_global->menuItemIdHi = (current_spot2->object_id & 0xFF00) >> 8;
+ debug("noclic: new glob3,2 = %2X %2X", p_global->menuItemIdHi, p_global->menuItemIdLo);
+ affresult();
+ num &= 0xF0;
+ if(num != 0x30)
+ num = p_global->menuItemIdLo & 0xF0;
+ if(num == 0x30)
+ affcurseurs();
+}
+void generique()
+{
+ int oldmusic;
+ blackbars();
+ afficher();
+ fadetoblack(3);
+ ClearScreen();
+ oldmusic = p_global->currentMusicNum;
+ playhnm(95);
+ affpanel();
+ afftoppano();
+ needPaletteUpdate = 1;
+ startmusique(oldmusic);
+}
+void cancel2()
+{
+ afftopscr();
+ showobjects();
+ p_global->iconsIndex = 16;
+ p_global->drawFlags &= ~DrawFlags::drDrawMenu;
+ gametomiroir(1);
+}
+void testvoice()
+{
+ char res; //TODO: useless?
+ short num;
+ p_global->fresqNumber = 0;
+ p_global->perso_ptr = kPersons;
+ p_global->dialogType = DialogType::dtInspect;
+ num = (kPersons[0].id << 3) | p_global->dialogType;
+ res = dialoscansvmas((dial_t*)GetElem(gameDialogs, num));
+ restaurefondbulle();
+ af_subtitle();
+ persovox();
+ waitendspeak();
+ endpersovox();
+ p_global->ff_CA = 0;
+ p_global->dialogType = DialogType::dtTalk;
+}
+void load()
+{
+ char name[132];
+ unsigned char oldMusic, talk;
+ gameLoaded = 0;
+ oldMusic = p_global->currentMusicNum; //TODO: from ush to byte?!
+ fademusica0(1);
+ desktopcolors();
+ FlushEvents(-1, 0);
+// if(OpenDialog(0, 0)) //TODO: write me
+ {
+ // TODO
+ strcpy(name, "edsave1.000");
+ loadgame(name);
+ }
+ CLMouse_Hide();
+ CLBlitter_FillScreenView(-1);
+ fadetoblack(3);
+ CLBlitter_FillScreenView(0);
+ if(!gameLoaded)
+ {
+ mus_fade_flags = 3;
+ musicspy();
+ needPaletteUpdate = 1;
+ return;
+ }
+ if ((oldMusic & 0xFF) != p_global->currentMusicNum) //TODO: r30 is uns char/bug???
+ {
+ oldMusic = p_global->currentMusicNum;
+ p_global->currentMusicNum = 0;
+ startmusique(oldMusic);
+ }
+ else
+ {
+ mus_fade_flags = 3;
+ musicspy();
+ }
+ talk = p_global->autoDialog == 0xFF; //TODO check me
+ initafterload();
+ fadetoblack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(p_mainview, 0);
+ afftopscr();
+ p_global->inventoryScrollPos = 0;
+ showobjects();
+ maj_salle(p_global->roomNum);
+ if(talk)
+ {
+ p_global->iconsIndex = 4;
+ p_global->autoDialog = -1;
+ parle_moi();
+ }
+
+}
+void initafterload()
+{
+ p_global->perso_img_bank = 0;
+ p_global->lastSalNum = 0;
+ loadsal(p_global->area_ptr->salNum);
+ gameIcons[18].cursor_id |= 0x8000;
+ if(p_global->curAreaType == AreaType::atValley)
+ gameIcons[18].cursor_id &= ~0x8000;
+ kPersoRoomBankTable[30] = 27;
+ if(p_global->phaseNum >= 352)
+ kPersoRoomBankTable[30] = 26;
+ animateTalking = 0;
+ animationActive = 0;
+ p_global->ff_100 = 0;
+ p_global->eventType = EventType::etEventC;
+ p_global->valleyVidNum = 0;
+ p_global->drawFlags &= ~DrawFlags::drDrawMenu;
+ currentTime = TimerTicks / 100;
+ p_global->gameTime = currentTime;
+ if(p_global->roomPersoType == PersonFlags::pftTyrann)
+ chronoon(3000);
+ saved_repadam.x = -1;
+ saved_repadam.y = -1;
+}
+void save()
+{
+ char name[260];
+ fademusica0(1);
+ desktopcolors();
+ FlushEvents(-1, 0);
+ //SaveDialog(byte_37150, byte_37196->ff_A);
+ //TODO
+ strcpy(name, "edsave1.000");
+ savegame(name);
+ CLMouse_Hide();
+ CLBlitter_FillScreenView(0xFFFFFFFF);
+ fadetoblack(3);
+ CLBlitter_FillScreenView(0);
+ mus_fade_flags = 3;
+ musicspy();
+ needPaletteUpdate = 1;
+}
+void desktopcolors()
+{
+ fadetoblack(3);
+ CLBlitter_FillScreenView(-1);
+ CLPalette_BeSystem();
+ CLMouse_Show();
+}
+void panelrestart()
+{
+ unsigned char curmus, curlng;
+ gameLoaded = 0;
+ curmus = p_global->currentMusicNum;
+ curlng = p_global->pref_language;
+ loadrestart();
+ p_global->pref_language = curlng;
+ if(!gameLoaded) //TODO always?
+ return;
+ p_global->perso_img_bank = 0;
+ p_global->lastSalNum = 0;
+ loadsal(p_global->area_ptr->salNum);
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ gameIcons[18].cursor_id |= 0x8000;
+ if(p_global->curAreaType == AreaType::atValley)
+ gameIcons[18].cursor_id &= ~0x8000;
+ kPersoRoomBankTable[30] = 27;
+ if(p_global->phaseNum >= 352)
+ kPersoRoomBankTable[30] = 26;
+ animateTalking = 0;
+ animationActive = 0;
+ p_global->ff_100 = 0;
+ p_global->eventType = 0;
+ p_global->valleyVidNum = 0;
+ p_global->drawFlags &= ~DrawFlags::drDrawMenu;
+ p_global->inventoryScrollPos = 0;
+ saved_repadam.x = -1;
+ saved_repadam.y = -1;
+ if(curmus != p_global->currentMusicNum)
+ {
+ curmus = p_global->currentMusicNum;
+ p_global->currentMusicNum = 0;
+ startmusique(curmus);
+ }
+ fadetoblack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(p_mainview, 0);
+ afftopscr();
+ showobjects();
+ sauvefrises();
+ showBlackBars = 1;
+ maj_salle(p_global->roomNum);
+}
+void reallyquit()
+{
+ quit_flag3 = 1; //TODO: byte
+ quit_flag2 = 1;
+}
+void confirmer(char mode, char yesId)
+{
+ p_global->iconsIndex = 119;
+ gameIcons[119].object_id = yesId;
+ confirmMode = mode;
+ use_bank(65);
+ noclipax(12, 117, 74);
+ curs_x = 156;
+ if(pomme_q)
+ curs_x = 136;
+ curs_y = 88;
+}
+void confirmyes()
+{
+ affpanel();
+ p_global->iconsIndex = 85;
+ switch(confirmMode)
+ {
+ case 1: panelrestart(); break;
+ case 2: reallyquit(); break;
+ }
+}
+void confirmno()
+{
+ affpanel();
+ p_global->iconsIndex = 85;
+ pomme_q = 0;
+}
+void restart()
+{
+ confirmer(1, current_spot2->object_id);
+}
+void EdenQuit()
+{
+ confirmer(2, current_spot2->object_id);
+}
+void choixsubtitle()
+{
+ unsigned char lang = current_spot2->object_id & 0xF;
+ if(lang == p_global->pref_language)
+ return;
+ if(lang > 5)
+ return;
+ p_global->pref_language = lang;
+ langbuftopanel();
+ afflangue();
+}
+void reglervol()
+{
+ unsigned char *valptr = &p_global->pref_10C[current_spot2->object_id & 7];
+ curs_y = 104 - ((*valptr >> 2) & 0x3F); // TODO: check me
+ cur_slider_value_ptr = valptr;
+ p_global->menuFlags |= MenuFlags::mfFlag1;
+ if(current_spot2->object_id & 8)
+ p_global->menuFlags |= MenuFlags::mfFlag2;
+ cur_slider_x = current_spot2->sx;
+ cur_slider_y = curs_y;
+}
+void changervol()
+{
+ short delta;
+ if(mouse_held)
+ {
+ limitezonecurs(cur_slider_x - 1, cur_slider_x + 3, 40, 110);
+ delta = cur_slider_y - curs_y;
+ if(delta == 0)
+ return;
+ newvol(cur_slider_value_ptr, delta);
+ if(p_global->menuFlags & MenuFlags::mfFlag2)
+ newvol(cur_slider_value_ptr + 1, delta);
+ cursbuftopanel();
+ affcurseurs();
+ cur_slider_y = curs_y;
+ }
+ else
+ p_global->menuFlags &= ~(MenuFlags::mfFlag1 | MenuFlags::mfFlag2);
+}
+void newvol(unsigned char *volptr, short delta)
+{
+ short vol = *volptr / 4;
+ vol += delta;
+ if(vol < 0)
+ vol = 0;
+ if(vol > 63)
+ vol = 63;
+ *volptr = vol * 4;
+ CLSoundChannel_SetVolumeLeft(music_channel, p_global->pref_10C[0]); //TODO: this val only?
+ CLSoundChannel_SetVolumeRight(music_channel, p_global->pref_10C[1]);
+}
+void playtape()
+{
+ unsigned short oldRoomNum, oldParty;
+ unsigned char oldBack;
+ perso_t *oldPerso;
+ if(p_global->menuItemIdHi & 8)
+ p_global->tape_ptr++;
+ for(;;p_global->tape_ptr++)
+ {
+ if(p_global->tape_ptr == &tapes[MAX_TAPES])
+ {
+ p_global->tape_ptr--;
+ stoptape();
+ return;
+ }
+ if(p_global->tape_ptr->textNum)
+ break;
+ }
+ p_global->menuFlags |= MenuFlags::mfFlag8;
+ p_global->drawFlags &= ~DrawFlags::drDrawMenu;
+ oldRoomNum = p_global->roomNum;
+ oldParty = p_global->party;
+ oldBack = p_global->roomBgBankNum;
+ oldPerso = p_global->perso_ptr;
+ p_global->party = p_global->tape_ptr->party;
+ p_global->roomNum = p_global->tape_ptr->roomNum;
+ p_global->roomBgBankNum = p_global->tape_ptr->bgBankNum;
+ p_global->dialog_ptr = p_global->tape_ptr->dialog;
+ p_global->perso_ptr = p_global->tape_ptr->perso;
+ endpersovox();
+ affcurstape();
+ if(p_global->perso_ptr != oldPerso
+ || p_global->roomNum != lastTapeRoomNum)
+ {
+ lastTapeRoomNum = p_global->roomNum;
+ p_global->curPersoAnimPtr = 0;
+ p_global->ff_CA = 0;
+ p_global->perso_img_bank = -1;
+ anim_perfin();
+ load_perso_cour();
+ }
+ af_fondperso();
+ p_global->textNum = p_global->tape_ptr->textNum;
+ my_bulle();
+ getdatasync();
+ showpersopanel();
+ persovox();
+ p_global->roomBgBankNum = oldBack;
+ p_global->party = oldParty;
+ p_global->roomNum = oldRoomNum;
+}
+void rewindtape()
+{
+ if(p_global->tape_ptr > tapes)
+ {
+ p_global->tape_ptr--;
+ p_global->menuFlags &= ~MenuFlags::mfFlag8;
+ affcurstape();
+ }
+}
+void depcurstape()
+{
+ int idx;
+ tape_t *tape;
+ if(mouse_held)
+ {
+ limitezonecurs(95, 217, 179, 183);
+ idx = (curs_x - 97); if(idx < 0) idx = 0; idx /= 8;
+ tape = tapes + idx;
+ if(tape >= tapes + 16) tape = tapes + 16 - 1;
+ if(tape != p_global->tape_ptr)
+ {
+ p_global->tape_ptr = tape;
+ affcurstape();
+ p_global->menuFlags &= ~MenuFlags::mfFlag8;
+ }
+ }
+ else
+ p_global->menuFlags &= ~MenuFlags::mfFlag4;
+}
+void affcurstape()
+{
+ int x;
+ if(p_global->drawFlags & DrawFlags::drDrawFlag8)
+ no_palette = 1;
+ use_bank(65);
+ noclipax(2, 0, 176);
+ x = (p_global->tape_ptr - tapes) * 8 + 97;
+ gameIcons[112].sx = x - 3;
+ gameIcons[112].ex = x + 3;
+ noclipax(5, x, 179);
+ no_palette = 0;
+}
+void forwardtape()
+{
+ if(p_global->tape_ptr < tapes + 16)
+ {
+ p_global->tape_ptr++;
+ p_global->menuFlags &= ~MenuFlags::mfFlag8;
+ affcurstape();
+ }
+}
+void stoptape()
+{
+ if(!(p_global->drawFlags & DrawFlags::drDrawFlag8))
+ return;
+ p_global->menuFlags &= ~MenuFlags::mfFlag8;
+ p_global->drawFlags &= ~DrawFlags::drDrawFlag8;
+ p_global->menuFlags |= MenuFlags::mfFlag10;
+ p_global->iconsIndex = 85;
+ p_global->perso_ptr = 0;
+ lastTapeRoomNum = 0;
+ endpersovox();
+ fin_perso();
+ affpanel();
+ afftoppano();
+ needPaletteUpdate = 1;
+}
+void cliccurstape()
+{
+ p_global->menuFlags |= MenuFlags::mfFlag4;
+}
+void paneltobuf()
+{
+ setRS1( 0, 16, 320 - 1, 169 - 1);
+ setRD1(320, 16, 640 - 1, 169 - 1);
+ CLBlitter_CopyViewRect(p_mainview, p_mainview, &rect_src, &rect_dst);
+}
+void cursbuftopanel()
+{
+ setRS1(434, 40, 525 - 1, 111 - 1);
+ setRD1(114, 40, 205 - 1, 111 - 1);
+ CLBlitter_CopyViewRect(p_mainview, p_mainview, &rect_src, &rect_dst);
+}
+void langbuftopanel()
+{
+ setRS1(328, 42, 407 - 1, 97 - 1);
+ setRD1( 8, 42, 87 - 1, 97 - 1);
+ CLBlitter_CopyViewRect(p_mainview, p_mainview, &rect_src, &rect_dst);
+}
+void affpanel()
+{
+ use_bank(65);
+ noclipax(0, 0, 16);
+ paneltobuf();
+ afflangue();
+ affcurseurs();
+ affcurstape();
+}
+void afflangue()
+{
+ use_bank(65);
+ if(p_global->pref_language < 0 //TODO: never happens
+ || p_global->pref_language > 5)
+ return;
+ noclipax(6, 8, p_global->pref_language * 9 + 43); //TODO: * FONT_HEIGHT
+ noclipax(7, 77, p_global->pref_language * 9 + 44);
+}
+void affcursvol(short x, short vol1, short vol2)
+{
+ short slider = 3;
+ if(lastMenuItemIdLo && (lastMenuItemIdLo & 9) != 1) //TODO check me
+ slider = 4;
+ noclipax(slider, x, 104 - vol1);
+ slider = 3;
+ if((lastMenuItemIdLo & 9) != 0)
+ slider = 4;
+ noclipax(slider, x + 12, 104 - vol2);
+}
+void affcurseurs()
+{
+ use_bank(65);
+ if(p_global->drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ curseurselect(48);
+ affcursvol(114, p_global->pref_10C[0] / 4, p_global->pref_10C[1] / 4);
+ curseurselect(50);
+ affcursvol(147, p_global->pref_10E[0] / 4, p_global->pref_10E[1] / 4);
+ curseurselect(52);
+ affcursvol(179, p_global->pref_110[0] / 4, p_global->pref_110[1] / 4);
+}
+void curseurselect(int itemId)
+{
+ lastMenuItemIdLo = p_global->menuItemIdLo;
+ if((lastMenuItemIdLo & ~9) != itemId)
+ lastMenuItemIdLo = 0;
+}
+void afftoppano()
+{
+ noclipax(1, 0, 0);
+}
+void affresult()
+{
+ short num;
+ restaurefondbulle();
+ p_global->perso_ptr = &kPersons[19];
+ p_global->dialogType = DialogType::dtInspect;
+ num = (kPersons[19].id << 3) | p_global->dialogType;
+ if(dialoscansvmas((dial_t*)GetElem(gameDialogs, num)))
+ af_subtitle();
+ p_global->ff_CA = 0;
+ p_global->dialogType = DialogType::dtTalk;
+ p_global->perso_ptr = 0;
+}
+void limitezonecurs(short xmin, short xmax, short ymin, short ymax)
+{
+ if(curs_x < xmin) curs_x = xmin;
+ if(curs_x > xmax) curs_x = xmax;
+ if(curs_y < ymin) curs_y = ymin;
+ if(curs_y > ymax) curs_y = ymax;
+}
+void PommeQ()
+{
+ icon_t *icon = &gameIcons[85];
+ if(p_global->displayFlags & DisplayFlags::dfFresques)
+ {
+ torchCursor = 0;
+ curs_saved = 1;
+ if(p_global->displayFlags & DisplayFlags::dfPerson)
+ close_perso();
+ p_global->displayFlags = DisplayFlags::dfFlag1;
+ resetscroll();
+ p_global->ff_100 = -1;
+ maj_salle(p_global->roomNum);
+ }
+ if(p_global->displayFlags & DisplayFlags::dfPerson)
+ close_perso();
+ if(p_global->displayFlags & DisplayFlags::dfPanable)
+ resetscroll();
+ if(p_global->displayFlags & DisplayFlags::dfMirror)
+ resetscroll();
+ if(p_global->drawFlags & DrawFlags::drDrawFlag8)
+ stoptape();
+ if(personTalking)
+ endpersovox();
+ p_global->ff_103 = 0;
+ p_global->ff_102 = 0;
+ putobject();
+ current_cursor = 53;
+ if(p_global->displayFlags != DisplayFlags::dfFlag2)
+ gotopanel();
+ current_spot2 = icon + 7; //TODO
+ EdenQuit();
+}
+void habitants(perso_t *perso)
+{
+ char persType = perso->flags & PersonFlags::pfTypeMask; //TODO rename
+ if(persType && persType != PersonFlags::pfType2)
+ {
+ p_global->room_perso = perso;
+ p_global->roomPersoType = persType;
+ p_global->roomPersoFlags = perso->flags;
+ p_global->roomPersoItems = perso->items;
+ p_global->roomPersoPowers = perso->powers;
+ p_global->partyOutside |= perso->party;
+ if(p_global->roomPersoType == PersonFlags::pftTriceraptor)
+ delinfo(p_global->areaNum + ValleyNews::vnTriceraptorsIn);
+ else
+ if(p_global->roomPersoType == PersonFlags::pftVelociraptor)
+ delinfo(p_global->areaNum + ValleyNews::vnVelociraptorsIn);
+ }
+ else
+ if (!(perso->flags & PersonFlags::pfInParty))
+ p_global->partyOutside |= perso->party;
+}
+void suiveurs(perso_t *perso)
+{
+ char persType = perso->flags & PersonFlags::pfTypeMask;
+ if(persType == 0 || persType == PersonFlags::pfType2)
+ {
+ if (perso->flags & PersonFlags::pfInParty)
+ p_global->party |= perso->party;
+ }
+}
+void evenements(perso_t *perso)
+{
+ if(p_global->ff_113)
+ return;
+ if(perso >= &kPersons[PER_UNKN_18C])
+ return;
+ if(!dialo_even(perso))
+ return;
+ p_global->ff_113++;
+ p_global->oldDisplayFlags = 1;
+ perso = p_global->perso_ptr;
+ init_perso_ptr(perso);
+ if (!(perso->party & PersonMask::pmLeader))
+ p_global->ff_60 = -1;
+ p_global->eventType = 0;
+}
+void followme(perso_t *perso)
+{
+ if(perso->flags & PersonFlags::pfTypeMask)
+ return;
+ if (perso->flags & PersonFlags::pfInParty)
+ perso->roomNum = destinationRoom;
+}
+void rangermammi(perso_t *perso, room_t *room)
+{
+ room_t *found_room;
+ if (!(perso->party & PersonMask::pmLeader))
+ return;
+ for(;room->ff_0 != 0xFF;room++)
+ {
+ if(room->flags & RoomFlags::rfHasCitadel)
+ {
+ found_room = room;
+ break;
+ }
+ if (room->party != 0xFFFF && (room->party & PersonMask::pmLeader))
+ found_room = room; //TODO: no brk?
+ }
+ if(!found_room) //TODO not zeroed?
+ return;
+ perso->roomNum &= ~0xFF;
+ perso->roomNum |= found_room->location;
+ perso->flags &= ~PersonFlags::pfInParty;
+ p_global->party &= ~perso->party;
+}
+void perso_ici(short action)
+{
+ perso_t *perso = &kPersons[PER_UNKN_156];
+// room_t *room = p_global->last_area_ptr->room_ptr; //TODO: compiler opt bug? causes access to zero ptr??? last_area_ptr == 0
+ switch(action)
+ {
+ case 0: suiveurs(perso); break;
+ case 1: habitants(perso); break;
+ case 3: evenements(perso); break;
+ case 4: followme(perso); break;
+ case 5: rangermammi(perso, p_global->last_area_ptr->citadelRoom); break;
+ }
+ perso = kPersons;
+ do
+ {
+ if (perso->roomNum == p_global->roomNum && !(perso->flags & PersonFlags::pf80))
+ {
+ switch(action)
+ {
+ case 0: suiveurs(perso); break;
+ case 1: habitants(perso); break;
+ case 3: evenements(perso); break;
+ case 4: followme(perso); break;
+ case 5: rangermammi(perso, p_global->last_area_ptr->citadelRoom); break;
+ }
+ }
+ perso++;
+ }
+ while(perso->roomNum != 0xFFFF);
+}
+void setpersohere()
+{
+ debug("setpersohere, perso is %d", p_global->perso_ptr - kPersons);
+ p_global->partyOutside = 0;
+ p_global->party = 0;
+ p_global->room_perso = 0;
+ p_global->roomPersoType = 0;
+ p_global->roomPersoFlags = 0;
+ perso_ici(1);
+ perso_ici(0);
+ if(p_global->roomPersoType == PersonFlags::pftTyrann) delinfo(p_global->areaNum + ValleyNews::vnTyrannIn);
+ if(p_global->roomPersoType == PersonFlags::pftTriceraptor) delinfo(p_global->areaNum + ValleyNews::vnTriceraptorsIn);
+ if(p_global->roomPersoType == PersonFlags::pftVelociraptor)
+ {
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannIn);
+ delinfo(p_global->areaNum + ValleyNews::vnTyrannLost);
+ delinfo(p_global->areaNum + ValleyNews::vnVelociraptorsLost);
+ }
+}
+void faire_suivre(short roomNum)
+{
+ destinationRoom = roomNum;
+ perso_ici(4);
+}
+void suis_moi5()
+{
+ debug("adding person %d to party", p_global->perso_ptr - kPersons);
+ p_global->perso_ptr->flags |= PersonFlags::pfInParty;
+ p_global->perso_ptr->roomNum = p_global->roomNum;
+ p_global->party |= p_global->perso_ptr->party;
+ p_global->drawFlags |= DrawFlags::drDrawTopScreen;
+}
+void suis_moi(short index)
+{
+ perso_t *old_perso = p_global->perso_ptr;
+ p_global->perso_ptr = &kPersons[index];
+ suis_moi5();
+ p_global->perso_ptr = old_perso;
+}
+void reste_ici5()
+{
+ debug("removing person %d from party", p_global->perso_ptr - kPersons);
+ p_global->perso_ptr->flags &= ~PersonFlags::pfInParty;
+ p_global->partyOutside |= p_global->perso_ptr->party;
+ p_global->party &= ~p_global->perso_ptr->party;
+ p_global->drawFlags |= DrawFlags::drDrawTopScreen;
+}
+void reste_ici(short index)
+{
+ perso_t *old_perso = p_global->perso_ptr;
+ p_global->perso_ptr = &kPersons[index];
+ reste_ici5();
+ p_global->perso_ptr = old_perso;
+}
+void eloipart()
+{
+ reste_ici(5);
+ p_global->gameFlags &= ~GameFlags::gfFlag4000;
+ kPersons[PER_MESSAGER].roomNum = 0;
+ p_global->partyOutside &= ~kPersons[PER_MESSAGER].party;
+ if(p_global->roomNum == 2817)
+ chronoon(3000);
+ p_global->eloiDepartureDay = p_global->gameDays;
+ p_global->eloiHaveNews = 0;
+ unlockinfo();
+}
+char eloirevientq()
+{
+ if(p_global->phaseNum < 304)
+ return 1;
+ if(p_global->phaseNum <= 353)
+ return 0;
+ if(p_global->phaseNum == 370)
+ return 0;
+ if(p_global->phaseNum == 384)
+ return 0;
+ if(p_global->areaNum != Areas::arShandovra)
+ return 1;
+ if(p_global->phaseNum < 480)
+ return 0;
+ return 1;
+}
+void eloirevient()
+{
+ if(p_global->area_ptr->type == AreaType::atValley && !kPersons[PER_MESSAGER].roomNum)
+ kPersons[PER_MESSAGER].roomNum = (p_global->roomNum & 0xFF00) + 1;
+}
+//// phase.c
+void incphase1()
+{
+ static phase_t phases[] = {
+ { 65, &EdenGameImpl::dialautoon },
+ { 113, &EdenGameImpl::phase113 },
+ { 129, &EdenGameImpl::dialautoon },
+ { 130, &EdenGameImpl::phase130 },
+ { 161, &EdenGameImpl::phase161 },
+ { 211, &EdenGameImpl::dialautoon },
+ { 226, &EdenGameImpl::phase226 },
+ { 257, &EdenGameImpl::phase257 },
+ { 353, &EdenGameImpl::phase353 },
+ { 369, &EdenGameImpl::phase369 },
+ { 371, &EdenGameImpl::phase371 },
+ { 385, &EdenGameImpl::phase385 },
+ { 386, &EdenGameImpl::dialonfollow },
+ { 418, &EdenGameImpl::phase418 },
+ { 433, &EdenGameImpl::phase433 },
+ { 434, &EdenGameImpl::phase434 },
+ { 449, &EdenGameImpl::dialautoon },
+ { 497, &EdenGameImpl::dialautoon },
+ { 513, &EdenGameImpl::phase513 },
+ { 514, &EdenGameImpl::phase514 },
+ { 529, &EdenGameImpl::phase529 },
+ { 545, &EdenGameImpl::phase545 },
+ { 561, &EdenGameImpl::phase561 },
+ { -1, nullptr }
+ };
+
+ phase_t *phase = phases;
+ p_global->phaseNum++;
+ debug("!!! next phase - %4X , room %4X", p_global->phaseNum, p_global->roomNum);
+ p_global->phaseActionsCount = 0;
+ for(;phase->id != -1;phase++)
+ {
+ if(p_global->phaseNum == phase->id)
+ {
+ (this->*phase->disp)();
+ break;
+ }
+ }
+}
+void incphase()
+{
+ incphase1();
+}
+void phase113()
+{
+ reste_ici(1);
+ kPersons[PER_DINA].roomNum = 274;
+}
+void phase130()
+{
+ dialautoon();
+ reste_ici(3);
+}
+void phase161()
+{
+ area_t *area = p_global->area_ptr;
+ suis_moi(9);
+ kPersons[PER_MAMMI].flags |= PersonFlags::pf10;
+ area->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+}
+void phase226()
+{
+ newobject(16, 3);
+ newobject(16, 4);
+ newobject(16, 5);
+}
+void phase257()
+{
+ gameIcons[127].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 58;
+ dialautooff();
+}
+void phase353()
+{
+ reste_ici(1);
+ kPersons[PER_DINA].roomNum = 0;
+ kTabletView[1] = 88;
+}
+void phase369()
+{
+ suis_moi(5);
+ p_global->narratorSequence = 2;
+ gameRooms[334].exits[0] = 134;
+ gameRooms[335].exits[0] = 134;
+}
+void phase371()
+{
+ eloirevient();
+ gameIcons[128].cursor_id &= ~0x8000;
+ gameIcons[129].cursor_id &= ~0x8000;
+ gameIcons[127].cursor_id |= 0x8000;
+ p_global->persoBackgroundBankIdx = 59;
+ gameRooms[334].exits[0] = -1;
+ gameRooms[335].exits[0] = -1;
+ gameIcons[123].object_id = 9;
+ gameIcons[124].object_id = 26;
+ gameIcons[125].object_id = 42;
+ gameIcons[126].object_id = 56;
+}
+void phase385()
+{
+ dialautooff();
+ eloirevient();
+ p_global->next_info_idx = 0;
+ p_global->last_info_idx = 0;
+ updateinfolist();
+ p_global->last_info = 0;
+}
+void phase418()
+{
+ loseobject(Objects::obHorn);
+ dialautoon();
+ suis_moi(4);
+}
+void phase433()
+{
+ dialautoon();
+ kPersons[PER_MAMMI_4].flags &= ~PersonFlags::pf80;
+ kPersons[PER_BOURREAU].flags &= ~PersonFlags::pf80;
+ setpersohere();
+ p_global->chrono_on = 0;
+ p_global->chrono = 0;
+}
+void phase434()
+{
+ p_global->roomNum = 275;
+ gameRooms[16].bank = 44;
+ gameRooms[18].bank = 44;
+ gameIcons[132].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 61;
+ gameRooms[118].exits[2] = -1;
+ abortdial();
+ gameRooms[7].bank = 322;
+ reste_ici(7);
+ reste_ici(3);
+ reste_ici(5);
+ reste_ici(18);
+ reste_ici(4);
+ p_global->drawFlags |= DrawFlags::drDrawTopScreen;
+}
+void phase513()
+{
+ p_global->last_dialog_ptr = 0;
+ byte_30AFE = 0;
+ dialautoon();
+}
+void phase514()
+{
+ gameRooms[123].exits[2] = 1;
+}
+void phase529()
+{
+ gameIcons[133].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 63;
+}
+void phase545()
+{
+}
+void phase561()
+{
+ p_global->narratorSequence = 10;
+}
+void bigphase1()
+{
+ static void (EdenGameImpl::*bigphases[])() = {
+ &EdenGameImpl::phase16,
+ &EdenGameImpl::phase32,
+ &EdenGameImpl::phase48,
+ &EdenGameImpl::phase64,
+ &EdenGameImpl::phase80,
+ &EdenGameImpl::phase96,
+ &EdenGameImpl::phase112,
+ &EdenGameImpl::phase128,
+ &EdenGameImpl::phase144,
+ &EdenGameImpl::phase160,
+ &EdenGameImpl::phase176,
+ &EdenGameImpl::phase192,
+ &EdenGameImpl::phase208,
+ &EdenGameImpl::phase224,
+ &EdenGameImpl::phase240,
+ &EdenGameImpl::phase256,
+ &EdenGameImpl::phase272,
+ &EdenGameImpl::phase288,
+ &EdenGameImpl::phase304,
+ &EdenGameImpl::phase320,
+ &EdenGameImpl::phase336,
+ &EdenGameImpl::phase352,
+ &EdenGameImpl::phase368,
+ &EdenGameImpl::phase384,
+ &EdenGameImpl::phase400,
+ &EdenGameImpl::phase416,
+ &EdenGameImpl::phase432,
+ &EdenGameImpl::phase448,
+ &EdenGameImpl::phase464,
+ &EdenGameImpl::phase480,
+ &EdenGameImpl::phase496,
+ &EdenGameImpl::phase512,
+ &EdenGameImpl::phase528,
+ &EdenGameImpl::phase544,
+ &EdenGameImpl::phase560
+ };
+
+ short phase = (p_global->phaseNum & ~3) + 0x10; //TODO: check me
+ debug("!!! big phase - %4X", phase);
+ p_global->phaseActionsCount = 0;
+ p_global->phaseNum = phase;
+ if(phase > 560)
+ return;
+ phase >>= 4;
+ (this->*bigphases[phase - 1])();
+}
+void bigphase()
+{
+ if(!(p_global->dialog_ptr->flags & DialogFlags::dfSpoken))
+ bigphase1();
+}
+void phase16()
+{
+ dialautoon();
+}
+void phase32()
+{
+ word_31E7A &= ~0x8000;
+}
+void phase48()
+{
+ gameRooms[8].exits[1] = 22;
+ dialautoon();
+}
+void phase64()
+{
+ suis_moi(1);
+ kPersons[PER_MESSAGER].roomNum = 259;
+}
+void phase80()
+{
+ kPersons[PER_THOO].roomNum = 0;
+}
+void phase96()
+{
+}
+void phase112()
+{
+ giveobject();
+}
+void phase128()
+{
+ suis_moi(1);
+ giveobject();
+}
+void phase144()
+{
+ suis_moi(5);
+ gameRooms[113].video = 0;
+ gameRooms[113].bank = 317;
+}
+void phase160()
+{
+}
+void phase176()
+{
+ dialonfollow();
+}
+void phase192()
+{
+ area_t *area = p_global->area_ptr;
+ suis_moi(10);
+ kPersons[PER_MAMMI_1].flags |= PersonFlags::pf10;
+ dialautoon();
+ area->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+}
+void phase208()
+{
+ eloirevient();
+}
+void phase224()
+{
+ gameIcons[126].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 57;
+ dialautooff();
+}
+void phase240()
+{
+ area_t *area = p_global->area_ptr;
+ suis_moi(11);
+ kPersons[PER_MAMMI_2].flags |= PersonFlags::pf10;
+ area->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+}
+void phase256()
+{
+ dialautoon();
+}
+void phase272()
+{
+ dialautoon();
+ p_global->eloiHaveNews = 0;
+}
+void phase288()
+{
+ oui();
+ kPersons[PER_MANGO].roomNum = 0;
+ reste_ici(6);
+ suis_moi(5);
+ p_global->narratorSequence = 8;
+}
+void phase304()
+{
+ area_t *area = p_global->area_ptr;
+ suis_moi(7);
+ suis_moi(14);
+ kPersons[PER_MAMMI_5].flags |= PersonFlags::pf10;
+ dialautoon();
+ area->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+}
+void phase320()
+{
+ dialonfollow();
+}
+void phase336()
+{
+ gameRooms[288].exits[0] = 135;
+ gameRooms[289].exits[0] = 135;
+ loseobject(p_global->curObjectId);
+ dialautoon();
+}
+void phase352()
+{
+ kPersoRoomBankTable[30] = 26;
+ kPersons[PER_EVE].bank = 9;
+ kPersons[PER_EVE].targetLoc = 8;
+ suiveurs_list[13].image = 2;
+ dialautoon();
+ gameRooms[288].exits[0] = -1;
+ gameRooms[289].exits[0] = -1;
+ gameRooms[288].flags &= ~RoomFlags::rf02;
+ gameRooms[289].flags &= ~RoomFlags::rf02;
+}
+void phase368()
+{
+ reste_ici(7);
+ dialautoon();
+ kPersons[PER_MESSAGER].roomNum = 1811;
+ kPersons[PER_DINA].roomNum = 1607;
+}
+void phase384()
+{
+ area_t *area = p_global->area_ptr;
+ suis_moi(7);
+ reste_ici(1);
+ dialautoon();
+ area->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+ eloipart();
+}
+void phase400()
+{
+ dialonfollow();
+ kPersons[PER_ROI].roomNum = 0;
+ kPersons[PER_MONK].roomNum = 259;
+ p_global->eloiHaveNews = 0;
+ kObjectLocations[20] = 259;
+}
+void phase416()
+{
+ suis_moi(3);
+ gameIcons[130].cursor_id &= ~0x8000;
+ p_global->persoBackgroundBankIdx = 60;
+ gameRooms[0].exits[0] = 138;
+}
+void phase432()
+{
+ p_global->narratorSequence = 3;
+ kPersons[PER_MAMMI_4].flags |= PersonFlags::pf80;
+ kPersons[PER_BOURREAU].flags |= PersonFlags::pf80;
+ kPersons[PER_MESSAGER].roomNum = 257;
+ gameRooms[0].exits[0] = -1;
+ p_global->drawFlags |= DrawFlags::drDrawTopScreen;
+}
+void phase448()
+{
+ dialautoon();
+ eloipart();
+}
+void phase464()
+{
+ p_global->area_ptr->flags |= AreaFlags::afFlag1;
+ p_global->curAreaFlags |= AreaFlags::afFlag1;
+ kPersons[PER_MAMMI_6].flags |= PersonFlags::pf10;
+ suis_moi(8);
+ p_global->cita_area_num = p_global->areaNum;
+ naitredino(8);
+}
+void phase480()
+{
+ giveobject();
+ newvallee();
+ eloirevient();
+ kTabletView[1] = 94;
+}
+void phase496()
+{
+ dialautoon();
+ p_global->last_dialog_ptr = 0;
+ byte_30AFE = 0;
+}
+void phase512()
+{
+ reste_ici(3);
+ reste_ici(7);
+ reste_ici(8);
+ reste_ici(18);
+}
+void phase528()
+{
+ p_global->narratorSequence = 11;
+ suis_moi(3);
+ suis_moi(5);
+ suis_moi(7);
+ suis_moi(8);
+ suis_moi(18);
+}
+void phase544()
+{
+ eloipart();
+ dialautoon();
+ reste_ici(8);
+ reste_ici(18);
+}
+void phase560()
+{
+ kPersons[PER_MESSAGER].roomNum = 3073;
+ gameRooms[127].exits[1] = 0;
+}
+//// saveload.c
+void savegame(char *name)
+{
+// filespec_t fs;
+// file_t handle;
+ long size;
+// CLFile_MakeStruct(0, 0, name, &fs);
+// CLFile_Create(&fs);
+// CLFile_SetFinderInfos(&fs, 'EDNS', 'LEDN');
+// CLFile_Open(&fs, 3, handle);
+
+ Common::OutSaveFile *handle = g_system->getSavefileManager()->openForSaving(name);
+ if (!handle)
+ return;
+
+#define CLFile_Write(h, ptr, size) \
+ debug("writing 0x%X bytes", *size); \
+ h->write(ptr, *size);
+
+ vavaoffsetout();
+ size = (char*)(&p_global->save_end) - (char*)(p_global);
+ CLFile_Write(handle, p_global, &size);
+ size = (char*)(&gameIcons[134]) - (char*)(&gameIcons[123]);
+ CLFile_Write(handle, &gameIcons[123], &size);
+ lieuoffsetout();
+ size = (char*)(&kAreasTable[12]) - (char*)(&kAreasTable[0]);
+ CLFile_Write(handle, &kAreasTable[0], &size);
+ size = (char*)(&gameRooms[423]) - (char*)(&gameRooms[0]);
+ CLFile_Write(handle, &gameRooms[0], &size);
+ size = (char*)(&objects[42]) - (char*)(&objects[0]);
+ CLFile_Write(handle, &objects[0], &size);
+ size = (char*)(&kObjectLocations[45]) - (char*)(&kObjectLocations[0]);
+ CLFile_Write(handle, &kObjectLocations[0], &size);
+ size = (char*)(&suiveurs_list[14]) - (char*)(&suiveurs_list[13]);
+ CLFile_Write(handle, &suiveurs_list[13], &size);
+ size = (char*)(&kPersons[55]) - (char*)(&kPersons[0]);
+ CLFile_Write(handle, &kPersons[0], &size);
+ bandeoffsetout();
+ size = (char*)(&tapes[16]) - (char*)(&tapes[0]);
+ CLFile_Write(handle, &tapes[0], &size);
+ size = (char*)(&kTabletView[6]) - (char*)(&kTabletView[0]);
+ CLFile_Write(handle, &kTabletView[0], &size);
+ size = (char*)(&gameDialogs[10240]) - (char*)(&gameDialogs[0]); //TODO: const size 10240
+ CLFile_Write(handle, &gameDialogs[0], &size);
+
+ delete handle;
+
+#undef CLFile_Write
+
+// CLFile_Close(handle);
+
+ vavaoffsetin();
+ lieuoffsetin();
+ bandeoffsetin();
+
+ debug("* Game saved to %s", name);
+}
+void loadrestart()
+{
+ assert(0); //TODO: this won't work atm - all snapshots are BE
+ long offs = 0;
+ long size;
+ size = (char*)(&p_global->save_end) - (char*)(p_global);
+ loadpartoffile(2495, p_global, offs, size);
+ offs += size;
+ vavaoffsetin();
+ size = (char*)(&gameIcons[134]) - (char*)(&gameIcons[123]);
+ loadpartoffile(2495, &gameIcons[123], offs, size);
+ offs += size;
+ size = (char*)(&kAreasTable[12]) - (char*)(&kAreasTable[0]);
+ loadpartoffile(2495, &kAreasTable[0], offs, size);
+ offs += size;
+ lieuoffsetin();
+ size = (char*)(&gameRooms[423]) - (char*)(&gameRooms[0]);
+ loadpartoffile(2495, &gameRooms[0], offs, size);
+ offs += size;
+ size = (char*)(&objects[42]) - (char*)(&objects[0]);
+ loadpartoffile(2495, &objects[0], offs, size);
+ offs += size;
+ size = (char*)(&kObjectLocations[45]) - (char*)(&kObjectLocations[0]);
+ loadpartoffile(2495, &kObjectLocations[0], offs, size);
+ offs += size;
+ size = (char*)(&suiveurs_list[14]) - (char*)(&suiveurs_list[13]);
+ loadpartoffile(2495, &suiveurs_list[13], offs, size);
+ offs += size;
+ size = (char*)(&kPersons[55]) - (char*)(&kPersons[0]);
+ loadpartoffile(2495, &kPersons[0], offs, size);
+ offs += size;
+ size = (char*)(&tapes[16]) - (char*)(&tapes[0]);
+ loadpartoffile(2495, &tapes[0], offs, size);
+ offs += size;
+ bandeoffsetin();
+ size = (char*)(&kTabletView[6]) - (char*)(&kTabletView[0]);
+ loadpartoffile(2495, &kTabletView[0], offs, size);
+ offs += size;
+ size = (char*)(&gameDialogs[10240]) - (char*)(&gameDialogs[0]); //TODO: const size 10240
+ loadpartoffile(2495, &gameDialogs[0], offs, size);
+ gameLoaded = 1;
+}
+void loadgame(char *name)
+{
+// filespec_t fs;
+// file_t handle;
+ long size;
+// CLFile_MakeStruct(0, 0, name, &fs);
+// CLFile_Open(&fs, 3, handle);
+
+ Common::InSaveFile *handle = g_system->getSavefileManager()->openForLoading(name);
+ if (!handle)
+ return;
+
+#define CLFile_Read(h, ptr, size) \
+ h->read(ptr, *size);
+
+ size = (char*)(&p_global->save_end) - (char*)(p_global);
+ CLFile_Read(handle, p_global, &size);
+ vavaoffsetin();
+ size = (char*)(&gameIcons[134]) - (char*)(&gameIcons[123]);
+ CLFile_Read(handle, &gameIcons[123], &size);
+ size = (char*)(&kAreasTable[12]) - (char*)(&kAreasTable[0]);
+ CLFile_Read(handle, &kAreasTable[0], &size);
+ lieuoffsetin();
+ size = (char*)(&gameRooms[423]) - (char*)(&gameRooms[0]);
+ CLFile_Read(handle, &gameRooms[0], &size);
+ size = (char*)(&objects[42]) - (char*)(&objects[0]);
+ CLFile_Read(handle, &objects[0], &size);
+ size = (char*)(&kObjectLocations[45]) - (char*)(&kObjectLocations[0]);
+ CLFile_Read(handle, &kObjectLocations[0], &size);
+ size = (char*)(&suiveurs_list[14]) - (char*)(&suiveurs_list[13]);
+ CLFile_Read(handle, &suiveurs_list[13], &size);
+ size = (char*)(&kPersons[55]) - (char*)(&kPersons[0]);
+ CLFile_Read(handle, &kPersons[0], &size);
+ size = (char*)(&tapes[16]) - (char*)(&tapes[0]);
+ CLFile_Read(handle, &tapes[0], &size);
+ bandeoffsetin();
+ size = (char*)(&kTabletView[6]) - (char*)(&kTabletView[0]);
+ CLFile_Read(handle, &kTabletView[0], &size);
+ size = (char*)(&gameDialogs[10240]) - (char*)(&gameDialogs[0]); //TODO: const size 10240
+ CLFile_Read(handle, &gameDialogs[0], &size);
+
+ delete handle;
+#undef CLFile_Read
+
+// CLFile_Close(handle);
+ gameLoaded = 1;
+ debug("* Game loaded from %s", name);
+}
+#define NULLPTR (void*)0xFFFFFF
+#define OFSOUT(val, base, typ) if(val) (val) = (typ*)((char*)(val) - (size_t)(base)); else (val) = (typ*)NULLPTR;
+#define OFSIN(val, base, typ) if((void*)(val) != NULLPTR) (val) = (typ*)((char*)(val) + (size_t)(base)); else (val) = 0;
+void vavaoffsetout()
+{
+ OFSOUT(p_global->dialog_ptr, gameDialogs, dial_t);
+ OFSOUT(p_global->next_dialog_ptr, gameDialogs, dial_t);
+ OFSOUT(p_global->narrator_dialog_ptr, gameDialogs, dial_t);
+ OFSOUT(p_global->last_dialog_ptr, gameDialogs, dial_t);
+ OFSOUT(p_global->tape_ptr, tapes, tape_t);
+ OFSOUT(p_global->nextRoomIcon, gameIcons, icon_t);
+ OFSOUT(p_global->room_ptr, gameRooms, room_t);
+ OFSOUT(p_global->cita_area_firstRoom, gameRooms, room_t);
+ OFSOUT(p_global->area_ptr, kAreasTable, area_t);
+ OFSOUT(p_global->last_area_ptr, kAreasTable, area_t);
+ OFSOUT(p_global->cur_area_ptr, kAreasTable, area_t);
+ OFSOUT(p_global->perso_ptr, kPersons, perso_t);
+ OFSOUT(p_global->room_perso, kPersons, perso_t);
+}
+void vavaoffsetin()
+{
+ OFSIN(p_global->dialog_ptr, gameDialogs, dial_t);
+ OFSIN(p_global->next_dialog_ptr, gameDialogs, dial_t);
+ OFSIN(p_global->narrator_dialog_ptr, gameDialogs, dial_t);
+ OFSIN(p_global->last_dialog_ptr, gameDialogs, dial_t);
+ OFSIN(p_global->tape_ptr, tapes, tape_t);
+ OFSIN(p_global->nextRoomIcon, gameIcons, icon_t);
+ OFSIN(p_global->room_ptr, gameRooms, room_t);
+ OFSIN(p_global->cita_area_firstRoom, gameRooms, room_t);
+ OFSIN(p_global->area_ptr, kAreasTable, area_t);
+ OFSIN(p_global->last_area_ptr, kAreasTable, area_t);
+ OFSIN(p_global->cur_area_ptr, kAreasTable, area_t);
+ OFSIN(p_global->perso_ptr, kPersons, perso_t);
+ OFSIN(p_global->room_perso, kPersons, perso_t);
+}
+void lieuoffsetout()
+{
+ int i;
+ for(i = 0;i < 12;i++)
+ {
+ OFSOUT(kAreasTable[i].citadelRoom, gameRooms, room_t);
+ }
+}
+void lieuoffsetin()
+{
+ int i;
+ for(i = 0;i < 12;i++)
+ {
+ OFSIN(kAreasTable[i].citadelRoom, gameRooms, room_t);
+ }
+}
+void bandeoffsetout()
+{
+ int i;
+ for(i = 0;i < 16;i++)
+ {
+ OFSOUT(tapes[i].perso, kPersons, perso_t);
+ OFSOUT(tapes[i].dialog, gameDialogs, dial_t);
+ }
+}
+void bandeoffsetin()
+{
+ int i;
+ for(i = 0;i < 16;i++)
+ {
+ OFSIN(tapes[i].perso, kPersons, perso_t);
+ OFSIN(tapes[i].dialog, gameDialogs, dial_t);
+ }
+}
+//// cond.c
+
+unsigned char *code_ptr;
+
+char testcondition(short index)
+{
+ char end = 0;
+ unsigned char op;
+ unsigned short value, value2;
+ unsigned short stack[32], *sp = stack, *sp2;
+ unsigned short ofs;
+ assert(index > 0);
+ code_ptr = (unsigned char*)GetElem(gameConditions, (index - 1));
+ do
+ {
+ value = cher_valeur();
+ for(;;)
+ {
+ op = *code_ptr++;
+ if(op == 0xFF)
+ {
+ end = 1;
+ break;
+ }
+ if((op & 0x80) == 0)
+ {
+ value2 = cher_valeur();
+ value = operation(op, value, value2);
+ }
+ else
+ {
+ assert(sp < stack + 32);
+ *sp++ = value;
+ *sp++ = op;
+ break;
+ }
+ }
+ }
+ while(!end);
+
+ if(sp != stack)
+ {
+ *sp++ = value;
+ sp2 = stack;
+ value = *sp2++;
+ do
+ {
+ op = *sp2++;
+ value2 = *sp2++;
+ value = operation(op, value, value2);
+ }
+ while(sp2 != sp);
+ }
+// if (value)
+ debug("cond %d(-1) returns %s", index, value ? "TRUE" : "false");
+// if (index == 402) debug("(glob_61.b == %X) & (glob_12.w == %X) & (glob_4C.b == %X) & (glob_4E.b == %X)", p_global->eventType, p_global->phaseNum, p_global->worldTyrannSighted, p_global->ff_4E);
+ return value != 0;
+}
+unsigned short opera_add(unsigned short v1, unsigned short v2) { return v1 + v2; }
+unsigned short opera_sub(unsigned short v1, unsigned short v2) { return v1 - v2; }
+unsigned short opera_and(unsigned short v1, unsigned short v2) { return v1 & v2; }
+unsigned short opera_or(unsigned short v1, unsigned short v2) { return v1 | v2; }
+unsigned short opera_egal(unsigned short v1, unsigned short v2) { return v1 == v2 ? -1 : 0; }
+unsigned short opera_petit(unsigned short v1, unsigned short v2) { return v1 < v2 ? -1 : 0; } //TODO: all comparisons are unsigned!
+unsigned short opera_grand(unsigned short v1, unsigned short v2) { return v1 > v2 ? -1 : 0; }
+unsigned short opera_diff(unsigned short v1, unsigned short v2) { return v1 != v2 ? -1 : 0; }
+unsigned short opera_petega(unsigned short v1, unsigned short v2) { return v1 <= v2 ? -1 : 0; }
+unsigned short opera_graega(unsigned short v1, unsigned short v2) { return v1 >= v2 ? -1 : 0; }
+unsigned short opera_faux(unsigned short v1, unsigned short v2) { return 0; }
+unsigned short operation(unsigned char op, unsigned short v1, unsigned short v2)
+{
+ static unsigned short(EdenGameImpl::*operations[16])(unsigned short, unsigned short) = {
+ &EdenGameImpl::opera_egal,
+ &EdenGameImpl::opera_petit,
+ &EdenGameImpl::opera_grand,
+ &EdenGameImpl::opera_diff,
+ &EdenGameImpl::opera_petega,
+ &EdenGameImpl::opera_graega,
+ &EdenGameImpl::opera_add,
+ &EdenGameImpl::opera_sub,
+ &EdenGameImpl::opera_and,
+ &EdenGameImpl::opera_or,
+ &EdenGameImpl::opera_faux,
+ &EdenGameImpl::opera_faux,
+ &EdenGameImpl::opera_faux,
+ &EdenGameImpl::opera_faux,
+ &EdenGameImpl::opera_faux,
+ &EdenGameImpl::opera_faux
+ };
+ return (this->*operations[(op & 0x1F) >> 1])(v1, v2);
+}
+unsigned short cher_valeur()
+{
+ unsigned short val;
+ unsigned char typ = *code_ptr++;
+ if(typ < 0x80)
+ {
+ unsigned char ofs = *code_ptr++;
+ if(typ == 1)
+ val = *(unsigned char*)(ofs + (unsigned char*)p_global);
+ else
+ val = *(unsigned short*)(ofs + (unsigned char*)p_global);
+ }
+ else if(typ == 0x80)
+ val = *code_ptr++;
+ else
+ {
+ val = PLE16(code_ptr);
+ code_ptr += 2;
+ }
+ return val;
+}
+void monbreak()
+{
+ assert(0);
+ signon(" coucou");
+}
+void ret()
+{
+}
+//// cube.c
+short tabcos[361 * 2];
+int dword_32424, dword_32428, dword_3242C;
+int dword_32430, dword_32434, dword_32438;
+int dword_3243C, dword_32440, dword_32444;
+short word_32448;
+short word_3244A, word_3244C;
+float flt_32450, flt_32454;
+cube_t cube;
+short curs_cur_map;
+short lines[200 * 8];
+unsigned char cube_texture[0x4000];
+int cube_faces;
+long curs_old_tick, curs_new_tick;
+
+void make_tabcos()
+{
+ int i;
+ for(i = 0;i < 361;i++)
+ {
+ tabcos[i * 2] = (int)(cos(3.1416 * i / 180.0) * 255.0);
+ tabcos[i * 2 + 1] = (int)(sin(3.1416 * i / 180.0) * 255.0);
+ }
+}
+void make_matrice_fix()
+{
+ short r30, r28, r29;
+ r30 = word_3244C;
+ r28 = word_3244A;
+ r29 = word_32448;
+
+ dword_32424 = (tabcos[r29 * 2] * tabcos[r28 * 2]) >> 8;
+ dword_32430 = (tabcos[r29 * 2 + 1] * tabcos[r28 * 2]) >> 8;
+ dword_3243C = -tabcos[r28 * 2 + 1];
+ dword_32428 = ((-tabcos[r29 * 2 + 1] * tabcos[r30 * 2]) >> 8)
+ + ((tabcos[r30 * 2 + 1] * ((tabcos[r29 * 2] * tabcos[r28 * 2 + 1]) >> 8)) >> 8);
+ dword_32434 = ((tabcos[r29 * 2] * tabcos[r30 * 2]) >> 8)
+ + ((tabcos[r30 * 2 + 1] * ((tabcos[r29 * 2 + 1] * tabcos[r28 * 2 + 1]) >> 8)) >> 8);
+ dword_32440 = (tabcos[r28 * 2] * tabcos[r30 * 2 + 1]) >> 8;
+ dword_3242C = ((tabcos[r29 * 2 + 1] * tabcos[r30 * 2 + 1]) >> 8)
+ + ((tabcos[r30 * 2] * ((tabcos[r29 * 2] * tabcos[r28 * 2 + 1]) >> 8)) >> 8);
+ dword_32438 = ((-tabcos[r29 * 2] * tabcos[r30 * 2 + 1]) >> 8)
+ + ((tabcos[r30 * 2] * ((tabcos[r29 * 2 + 1] * tabcos[r28 * 2 + 1]) >> 8)) >> 8);
+ dword_32444 = (tabcos[r28 * 2] * tabcos[r30 * 2]) >> 8;
+}
+void projection_fix(cube_t *cube, int n)
+{
+ int i;
+ for(i = 0;i < n;i++)
+ {
+ int r24, r25, r26, r27, r28, r29;
+ r28 = cube->vertices[i * 4];
+ r27 = cube->vertices[i * 4 + 1];
+ r26 = cube->vertices[i * 4 + 2];
+
+ r25 = dword_32424 * r28 + dword_32428 * r27 + dword_3242C * r26 + (int)(flt_32454 * 256.0f);
+ r24 = dword_32430 * r28 + dword_32434 * r27 + dword_32438 * r26 + (int)(flt_32450 * 256.0f);
+ r29 = dword_3243C * r28 + dword_32440 * r27 + dword_32444 * r26 + (int)(flt_2DF7C * 256.0f);
+
+ r29 >>= 8;
+ if(r29 == -256)
+ r29++;
+ cube->projection[i * 4 ] = r25 / (r29 + 256) + curs_x + 14 + scroll_pos;
+ cube->projection[i * 4 + 1] = r24 / (r29 + 256) + curs_y + 14;
+ cube->projection[i * 4 + 2] = r29;
+
+// assert(cube->projection[i * 4] < 640);
+// assert(cube->projection[i * 4 + 1] < 200);
+ }
+}
+void init_cube()
+{
+ NEWcharge_map(2493, cube_texture);
+ NEWcharge_objet_mob(&cube, 2494, cube_texture);
+ make_tabcos();
+}
+void moteur()
+{
+ Eden_dep_and_rot();
+ make_matrice_fix();
+ projection_fix(&cube, cube_faces);
+ affiche_objet(&cube);
+}
+void affiche_objet(cube_t *cube)
+{
+ int i;
+ for(i = 0;i < cube->num;i++)
+ affiche_polygone_mapping(cube, cube->faces[i]);
+}
+void NEWcharge_map(int file_id, unsigned char *buffer)
+{
+ int i;
+ loadpartoffile(file_id, buffer, 32, 256 * 3);
+
+ for(i = 0;i < 256;i++)
+ {
+ color3_t color;
+ color.r = buffer[i * 3] << 8;
+ color.g = buffer[i * 3 + 1] << 8;
+ color.b = buffer[i * 3 + 2] << 8;
+ CLPalette_SetRGBColor(global_palette, i, &color);
+ }
+ CLPalette_Send2Screen(global_palette, 0, 256);
+
+ loadpartoffile(file_id, buffer, 32 + 256 * 3, 0x4000);
+}
+void NEWcharge_objet_mob(cube_t *cube, int file_id, unsigned char *texptr)
+{
+ int i, j, count2;
+ char *tmp1, *next, error;
+ cubeface_t **tmp4;
+ short *vertices, *projection;
+ tmp1 = (char*)malloc(454);
+ loadpartoffile(file_id, tmp1, 0, 454);
+ next = tmp1;
+ cube_faces = next_val(&next, &error);
+ vertices = (short*)malloc(cube_faces * 4 * sizeof(*vertices));
+ projection = (short*)malloc(cube_faces * 4 * sizeof(*projection));
+ for(i = 0;i < cube_faces;i++)
+ {
+ vertices[i * 4] = next_val(&next, &error);
+ vertices[i * 4 + 1] = next_val(&next, &error);
+ vertices[i * 4 + 2] = next_val(&next, &error);
+ }
+ count2 = next_val(&next, &error);
+ tmp4 = (cubeface_t**)malloc(count2 * sizeof(*tmp4));
+ for(i = 0;i < count2;i++)
+ {
+ char textured;
+ tmp4[i] = (cubeface_t*)malloc(sizeof(cubeface_t));
+ tmp4[i]->tri = 3;
+ textured = next_val(&next, &error);
+ tmp4[i]->ff_5 = next_val(&next, &error);
+ tmp4[i]->indices = (unsigned short*)malloc(3 * sizeof(*tmp4[i]->indices));
+ tmp4[i]->uv = (short*)malloc(3 * 2 * sizeof(*tmp4[i]->uv));
+ for(j = 0;j < 3;j++)
+ {
+ tmp4[i]->indices[j] = next_val(&next, &error);
+ if(textured)
+ {
+ tmp4[i]->uv[j * 2] = next_val(&next, &error);
+ tmp4[i]->uv[j * 2 + 1] = next_val(&next, &error);
+ }
+ }
+ if(textured)
+ {
+ tmp4[i]->ff_4 = 3;
+ tmp4[i]->texptr = texptr;
+ }
+ else
+ tmp4[i]->ff_4 = 0;
+ }
+ free(tmp1);
+ cube->num = count2;
+ cube->faces = tmp4;
+ cube->projection = projection;
+ cube->vertices = vertices;
+}
+static int next_val(char **ptr, char *error)
+{
+ char c = 0;
+ char *p = *ptr;
+ int val = strtol(p, 0, 10);
+ while((*p >= '0' && *p <= '9' && *p != 0) || *p == '-') p++;
+ while((*p == 13 || *p == 10 || *p == ',' || *p == ' ') && *p) c = *p++;
+ *error = c == 10;
+ *ptr = p;
+ return val;
+}
+void selectmap(short num)
+{
+ int i, j;
+ short k, x, y;
+ char mode;
+ curs_cur_map = num;
+ k = 0;
+ mode = tab_2E138[num];
+ x = (num & 7) * 32;
+ y = (num & 0x18) * 4;
+ for(i = 0;i < 6 * 2;i++)
+ for(j = 0;j < 3;j++)
+ {
+ cube.faces[i]->uv[j * 2 ] = x + cube_texcoords[mode][k]; k++;
+ cube.faces[i]->uv[j * 2 + 1] = y + cube_texcoords[mode][k]; k++;
+ }
+}
+void Eden_dep_and_rot()
+{
+ short curs;
+ curs = current_cursor;
+ if(normalCursor && (p_global->drawFlags & DrawFlags::drDrawFlag20))
+ curs = 10;
+ selectmap(curs);
+ curs_new_tick = TickCount();
+ if(curs_new_tick - curs_old_tick < 1)
+ return;
+ curs_old_tick = curs_new_tick;
+ switch(current_cursor)
+ {
+ case 0:
+ word_3244C = (word_3244C + 2) % 360;
+ word_3244A = (word_3244A + 2) % 360;
+ restoreZDEP();
+ break;
+ case 1:
+ word_3244C = 0;
+ word_3244A -= 2;
+ if(word_3244A < 0)
+ word_3244A += 360;
+ restoreZDEP();
+ break;
+ case 2:
+ word_3244C = (word_3244C + 2) % 360;
+ word_3244A = 0;
+ restoreZDEP();
+ break;
+ case 3:
+ word_3244C -= 2;
+ if(word_3244C < 0)
+ word_3244C += 360;
+ word_3244A = 0;
+ restoreZDEP();
+ break;
+ case 4:
+ word_3244C = 0;
+ word_3244A = (word_3244A + 2) % 360;
+ restoreZDEP();
+ break;
+ case 5:
+ word_3244C = 0;
+ word_3244A = 0;
+ flt_2DF7C += flt_2DF84;
+ if((flt_2DF7C < -3600.0 + flt_2DF80) || flt_2DF7C > flt_2DF80)
+ flt_2DF84 = -flt_2DF84;
+ break;
+ case 6:
+ word_3244C = 0;
+ word_3244A = 0;
+ flt_2DF7C = flt_2DF80;
+ break;
+ case 7:
+ word_3244C -= 2;
+ if(word_3244C < 0)
+ word_3244C += 360;
+ word_3244A = 0;
+ restoreZDEP();
+ break;
+ case 8:
+ word_3244C = 0;
+ word_3244A = 0;
+ flt_2DF7C = flt_2DF80;
+ break;
+ case 9:
+ word_3244C = 0;
+ word_3244A = 0;
+ flt_2DF7C = flt_2DF80;
+ break;
+ }
+}
+void restoreZDEP()
+{
+ flt_2DF84 = 200.0;
+ if(flt_2DF7C < flt_2DF80)
+ flt_2DF7C += flt_2DF84;
+ if(flt_2DF7C > flt_2DF80)
+ flt_2DF7C -= flt_2DF84;
+}
+void affiche_polygone_mapping(cube_t *cube, cubeface_t *face)
+{
+ short r20, r30, r26, r31, r19, r18, /*r25,*/ r24, ymin, ymax, v46, v48, v4A, v4C, v4E, v50;
+ short *uv;
+ unsigned short r25;
+ unsigned short *indices = face->indices;
+ int r17, r29;
+ r29 = indices[0] * 4;
+ v46 = cube->projection[r29];
+ v48 = cube->projection[r29 + 1];
+
+ r29 = indices[1] * 4;
+ v4A = cube->projection[r29];
+ v4C = cube->projection[r29 + 1];
+
+ r29 = indices[2] * 4;
+ v4E = cube->projection[r29];
+ v50 = cube->projection[r29 + 1];
+
+ if((v4C - v48) * (v4E - v46) - (v50 - v48) * (v4A - v46) > 0)
+ return;
+
+ uv = face->uv;
+ ymin = 200; // min y
+ ymax = 0; // max y
+ r29 = indices[0] * 4;
+ r20 = cube->projection[r29];
+ r30 = cube->projection[r29 + 1];
+ r19 = *uv++;
+ r18 = *uv++;
+ indices++;
+ for(r17 = 0;r17 < face->tri - 1;r17++, indices++)
+ {
+ r29 = indices[0] * 4;
+ r26 = cube->projection[r29];
+ r31 = cube->projection[r29 + 1];
+ r25 = *uv++; //TODO: unsigned
+ r24 = *uv++; //TODO: unsigned
+ if(r30 < ymin)
+ ymin = r30;
+ if(r30 > ymax)
+ ymax = r30;
+ if(r31 < ymin)
+ ymin = r31;
+ if(r31 > ymax)
+ ymax = r31;
+ trace_ligne_mapping(r20, r30, r26, r31, r19, r18, r25, r24, lines);
+ r20 = r26;
+ r30 = r31;
+ r19 = r25;
+ r18 = r24;
+ }
+ r29 = face->indices[0] * 4;
+ r26 = cube->projection[r29];
+ r31 = cube->projection[r29 + 1];
+ uv = face->uv;
+ r25 = *uv++; //TODO: this is unsigned
+ r24 = *uv; //TODO: this is signed
+ if(r30 < ymin)
+ ymin = r30;
+ if(r30 > ymax)
+ ymax = r30;
+ if(r31 < ymin)
+ ymin = r31;
+ if(r31 > ymax)
+ ymax = r31;
+ trace_ligne_mapping(r20, r30, r26, r31, r19, r18, r25, r24, lines);
+ affiche_ligne_mapping(ymin, ymax, p_mainview->p_buffer, face->texptr);
+}
+void trace_ligne_mapping(short r3, short r4, short r5, short r6, short r7, short r8, short r9, short r10, short *lines)
+{
+ short t;
+ short r26;
+ int r30, r29, r28, r23, r24, r25;
+ int i;
+ r26 = r6 - r4;
+ if(r26 <= 0)
+ {
+ if(r26 == 0)
+ {
+ lines += r4 * 8;
+ if(r5 - r3 > 0)
+ {
+ lines[0] = r3;
+ lines[1] = r5;
+ lines[4] = r7;
+ lines[5] = r9;
+ lines[6] = r8;
+ lines[7] = r10;
+ }
+ else
+ {
+ lines[0] = r5;
+ lines[1] = r3;
+ lines[4] = r9;
+ lines[5] = r7;
+ lines[6] = r10;
+ lines[7] = r8;
+ }
+ return;
+ }
+ t = r3; r3 = r5; r5 = t;
+ t = r7; r7 = r9; r9 = t;
+ t = r8; r8 = r10; r10 = t;
+ lines += r6 * 8;
+ r26 = -r26;
+ }
+ else
+ lines += r4 * 8 + 1; //TODO wha???
+
+ r30 = r3 << 16;
+ r29 = r7 << 16;
+ r28 = r8 << 16;
+
+ r25 = ((r5 - r3) << 16) / r26;
+ r24 = ((r9 - r7) << 16) / r26;
+ r23 = ((r10 - r8) << 16) / r26;
+
+ for(i = 0;i < r26;i++)
+ {
+ lines[0] = r30 >> 16;
+ lines[4] = r29 >> 16;
+ lines[6] = r28 >> 16;
+
+ r30 += r25;
+ r29 += r24;
+ r28 += r23;
+ lines += 8;
+ }
+}
+void affiche_ligne_mapping(short r3, short r4, unsigned char *target, unsigned char *texture)
+{
+ short r21, r20, r26, r25, r29, r28, len;
+ int r22;
+ unsigned short r31, r30;
+ short height = r4 - r3;
+ unsigned char *trg, *trg_line = p_mainview->p_buffer + r3 * 640; //TODO: target??
+ short *line = &lines[r3 * 8];
+// debug("curs: beg draw %d - %d", r3, r4);
+ for(r22 = height;r22;r22--, line += 8, trg_line += 640)
+ {
+ r29 = line[0];
+ r28 = line[1];
+ len = r28 - r29;
+ if(len < 0)
+ break;
+ if(len == 0)
+ continue;
+// debug("curs: lin draw %d", r4 - height);
+ r31 = line[4] << 8;
+ r30 = line[6] << 8;
+
+ r21 = line[5] - line[4];
+ r20 = line[7] - line[6];
+
+ r26 = (r21 << 8) / len;
+ r25 = (r20 << 8) / len;
+ trg = trg_line + r29;
+#if 1
+ while(r29++ < r28)
+ {
+ *trg++ = texture[(r30 & 0xFF00) | (r31 >> 8)];
+ r31 += r26;
+ r30 += r25;
+ }
+#endif
+ }
+}
+////// macgame.c
+//void MyDlgHook() { }
+//void PrepareReply() { }
+short OpenDialog(void *arg1, void *arg2)
+{
+ //TODO
+ return 0;
+}
+//void SaveDialog() { }
+//void LostEdenMac_SavePrefs() { }
+//void LostEdenMac_LoadPrefs() { }
+void LostEdenMac_InitPrefs()
+{
+ p_global->pref_language = 1;
+ doubled = 0; // TODO: set to 1
+ p_global->pref_10C[0] = 192;
+ p_global->pref_10C[1] = 192;
+ p_global->pref_10E[0] = 255;
+ p_global->pref_10E[1] = 255;
+ p_global->pref_110[0] = 32;
+ p_global->pref_110[1] = 32;
+}
+//void MacGame_DoAbout() { }
+//void MacGame_DoAdjustMenus() { }
+//void LostEdenMac_DoPreferences() { }
+//void MacGame_DoSave() { }
+//void MacGame_DoMenuCommand() { }
+//void MacGame_DoOpen() { }
+//void MacGame_DoSaveAs() { }
+
+}; // class EdenGameImpl
+
+EdenGameImpl LostEden;
+
+void EdenGame::main()
+{
+ LostEden.main();
+}
+
+} // namespace Cryo
diff --git a/engines/cryo/eden.h b/engines/cryo/eden.h
new file mode 100644
index 0000000000..c24f77abca
--- /dev/null
+++ b/engines/cryo/eden.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#define EDEN_DEBUG
+
+namespace Cryo {
+
+class EdenGame {
+public:
+ void main();
+};
+
+class EdenGameImpl;
+
+} \ No newline at end of file
diff --git a/engines/cryo/gameflow.txt b/engines/cryo/gameflow.txt
new file mode 100644
index 0000000000..33e5b0ed96
--- /dev/null
+++ b/engines/cryo/gameflow.txt
@@ -0,0 +1,24 @@
+
+game phases
+
+ 0 - game start
+ 10 - enter throne room
+ 20 - heard talk of eloi and father
+ 30 - in prince's room
+ 40 - met dina
+ 41 - talking to tau room: 202
+ 50 - tau died
+ 60 - talked to jabber
+ 70 - got a gift from jabber
+ 71 - part with dina at secret crypt
+ 80 - learned about fresques / got flute
+ 81 - convinced monk to help
+ 82 - enter throne room
+ 90 - got king's permission
+ A0 - met chong
+ A1 - chong joins party
+ B0 - on valley screen after citadel build complete
+ C0 - met ulan
+ D0 - build citadel in uluru
+ E0 - got gift from ulan
+ ...
diff --git a/engines/cryo/module.mk b/engines/cryo/module.mk
new file mode 100644
index 0000000000..4cda96472b
--- /dev/null
+++ b/engines/cryo/module.mk
@@ -0,0 +1,14 @@
+MODULE := engines/cryo
+
+MODULE_OBJS = \
+ cryo.o \
+ eden.o \
+ detection.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CRYO), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cryo/platdefs.h b/engines/cryo/platdefs.h
new file mode 100644
index 0000000000..8e4d0a3d05
--- /dev/null
+++ b/engines/cryo/platdefs.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#if 1
+#include "common/file.h"
+
+typedef Common::File file_t;
+
+struct filespec_t {
+char create;
+char name[260];
+};
+
+#if 1
+const int subtitles_x_margin = 16; //PC
+const int subtitles_x_scr_margin = 16;
+const int space_width = 6;
+#define FAKE_DOS_VERSION
+#else
+const int subtitles_x_margin = 16; //MAC
+const int subtitles_x_scr_margin = 16; //MAC
+const int space_width = 4;
+#endif
+const int subtitles_x_width = (320 - subtitles_x_margin * 2);
+const int subtitles_x_center = subtitles_x_width / 2;
+
+#endif
diff --git a/engines/cryo/readme.txt b/engines/cryo/readme.txt
new file mode 100644
index 0000000000..4c938c7897
--- /dev/null
+++ b/engines/cryo/readme.txt
@@ -0,0 +1,80 @@
+Citadel of Mo, the last remaining place where humans can be safe from army
+of vicious Tyrannosaurus led by allmighty Morkus Rex. What await young Adam,
+prince of Mo, who just came of age and want to travel across the world?
+Will he be able to restore long lost friendship between dinousaurus and humans?
+
+
+This is SCUMMVM reimplementation of Cryo's Lost Eden game engine. In order to
+stay as close as possible to original game and minimize number of bugs
+introduced during code reconstruction, in its current state this project is
+a straight reverse-engineered game code hooked up to SCUMMVM framework.
+Because of that, this code in no way represent the quality or coding practices
+of SCUMMVM itself. Essentially, this is how the game was originally written.
+
+There are few Lost Eden game versions known to exists.
+
+- Non-interactive PC demo version. Basically, a number of video files played
+ in a loop with FM music in background. Google for "ANCIBUR2.HNM" file to
+ find it.
+
+- Interactive PC demo version. Allows to play through whole Citadel of Mo
+ then shows "Order Now" banner.
+ Can be found here: http://www.ag.ru/games/lost-eden/demos/2677
+ Download is a self-extracting archive, unpack it with 7zip or other tool.
+
+- PC version. Main version of the game. Written in assembly and partially based
+ on Dune's game code.
+ Runs in real-mode DOS environment, uses VGA 320x200 graphics and digitized
+ sounds/music. Allows to select several languages for in-game subtitles. It is
+ rumored that bootleg Russian translation also exists. Has 3 predefined slots
+ for game save/load.
+
+- MAC version. Almost identical to PC version. Has slightly modified UI. Such
+ as exta spaces on the inventory bar, resized subtitles overlay and different
+ implementation of mouse cursor (which is worse than the original one). Looks
+ like screen transition effects are also changed / rearranged.
+ This version have no limit on save game slots. Standard system file selection
+ dialogs are used instead. All screen hot-spots coordinates loaded from
+ resource file instead of hard-coded values in PC version.
+
+- 3DO version. Uses completely different resource formats.
+
+- CDI version. Uses completely different resource formats.
+
+- CD32 version. Mentioned in PC demo version, but never released?
+
+
+This reimplementation project is based on MAC version, since it's much easier
+to work with than any other versions. As such, currently only MAC version
+supported. Adding support for PC versions shouldn't be too difficult and
+mainly involves implementing of proper resources indexing/loading. Game
+engine loads resources by their indexes in game archive file and these indexes
+are different between PC and MAC versions.
+
+At this moment the game is fully playabe/completeable. List of currently
+discovered bugs can be found in bugs.txt file. None of those are critical or
+game-breaking. No sound support is present in this version, although all
+sound front-end code is in place and should be operational. Only single
+game save/load slot is supported and saves are not cross-platform compatible.
+Also, no game restart feature work due to the way it's implemented.
+
+Due to the way original engine is coded, it is not fully portable in its
+current state. Game uses conditional dialog system (similar system is used in
+Dune game as well) and this system involves accessing native engine
+variables through predefined offsets within large structure. Any modification
+of this structure will result in broken dialog system.
+
+Because of limited development environment, this code is only tested on
+MSVS2013 32-bit compiler. There may be some issues with GCC/LLVM compilers
+or on 64-bit platforms. As mentioned above, this code is neither pretty or
+bug-free (aka it's a can of worms). Several original bugs, various oddities
+and problematic areas are marked with TODO comment in the source code. There
+are number of variables with non-descripitve names like byte_1234, those
+purpose is yet to be clearly understood. To make code debugging easier,
+EDEN_DEBUG macro activates several extra features. Some parts, like image
+drawing routines, can be simplified/generalized. Other parts, like CLView,
+can be replaced with existing SCUMMVM classes.
+
+Because parts of this code (mainly decompression and video playback) used
+by other Cryo's games, it might be worthy to make them reusable by future
+engines.