/* 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 "chamber/chamber.h" #include "chamber/common.h" #include "chamber/script.h" #include "chamber/resdata.h" #include "chamber/cga.h" #include "chamber/cursor.h" #include "chamber/portrait.h" #include "chamber/input.h" #include "chamber/menu.h" #include "chamber/room.h" #include "chamber/dialog.h" #include "chamber/print.h" #include "chamber/anim.h" #include "chamber/invent.h" #include "chamber/sound.h" #include "chamber/savegame.h" #if 1 #define DEBUG_SCRIPT char DEBUG_SCRIPT_LOG[] = "!script.log"; #endif #include "chamber/scrvars.h" namespace Chamber { unsigned char rand_seed; unsigned short the_command; unsigned int script_res; unsigned char *script_ptr, *script_end_ptr; unsigned char *script_stack[5 * 2]; unsigned char **script_stack_ptr = script_stack; void *script_vars[ScrPools_MAX] = { &script_word_vars, &script_word_vars, &script_byte_vars, inventory_items, zones_data, pers_list, inventory_items, inventory_items + 38, pers_list }; unsigned char Rand(void) { script_byte_vars.rand_value = aleat_data[++rand_seed]; return script_byte_vars.rand_value; } unsigned int RandW(void) { unsigned int r = Rand() << 8; return r | Rand(); } unsigned int Swap16(unsigned int x) { return (x << 8) | (x >> 8); } /*Script handlers exit codes*/ enum CommandStatus { ScriptContinue = 0, /*run next script command normally*/ ScriptRerun = 1, /*abort current script, execute new command*/ /*TODO: maybe define ScriptRestartGame to support game restart?*/ }; unsigned int CMD_TRAP(void) { printf("CMD TRAP\n"); PromptWait(); for (;;) ; return 0; } unsigned int SCR_TRAP(void) { printf("SCR TRAP 0x%02X @ 0x%X\n", *script_ptr, script_ptr - templ_data); PromptWait(); for (;;) ; return 0; } void ClaimTradedItems(void) { int i; for (i = 0; i < MAX_INV_ITEMS; i++) { if (inventory_items[i].flags == (ITEMFLG_80 | 1)) inventory_items[i].flags = ITEMFLG_80; } } unsigned int SCR_1_AspirantItemTrade(void) { unsigned char *old_script, *old_script_end = script_end_ptr; item_t *item1, *item2; script_ptr++; old_script = script_ptr; for (;;) { inv_bgcolor = 0xFF; OpenInventory(0xFE, ITEMFLG_80); if (inv_count == 0) { the_command = 0xC1BC; RunCommand(); break; } if (the_command == 0) { the_command = 0xC1C0; RunCommand(); break; } the_command = 0x9140; if (pers_ptr->item == 0) break; item1 = &inventory_items[pers_ptr->item - 1]; item2 = (item_t *)(script_vars[ScrPool3_CurrentItem]); if (item2->flags == (ITEMFLG_80 | 1) || item1->name == item2->name) { the_command = 0xC1C0; RunCommand(); break; } if (item2->name == 109 || item2->name == 132 || item2->name == 108 || script_byte_vars.rand_value < 154) { item2->flags = ITEMFLG_20; item1->flags = ITEMFLG_80; pers_ptr->item = script_byte_vars.inv_item_index; switch (item2->name) { case 132: script_byte_vars.room_items--; the_command = 0xC04B; break; case 104: the_command = 0xC1BA; break; case 107: the_command = 0xC1BB; break; default: the_command = 0xC1BA; } RunCommand(); break; } else { item2->flags = ITEMFLG_80 | 1; the_command = 0xC1BD; RunCommand(); continue; } } ClaimTradedItems(); script_ptr = old_script; script_end_ptr = old_script_end; return 0; } unsigned char wait_delta = 0; void Wait(unsigned char seconds) { struct time t; unsigned int endtime; seconds += wait_delta; if (seconds > 127) /*TODO: is this a check for an unsigned value?*/ seconds = 0; gettime(&t); endtime = t.ti_sec * 100 + t.ti_hund + seconds * 100; while (buttons == 0) { unsigned int current; gettime(&t); current = t.ti_sec * 100 + t.ti_hund; if (endtime >= 6000 && current < 2048) /*TODO: some kind of overflow check???*/ current += 6000; if (current >= endtime) break; } } unsigned int SCR_2C_Wait4(void) { script_ptr++; Wait(4); return 0; } unsigned int SCR_2D_Wait(void) { unsigned char seconds; script_ptr++; seconds = *script_ptr++; Wait(4); /*TODO: looks like a bug?*/ return 0; } unsigned int SCR_2E_PromptWait(void) { script_ptr++; PromptWait(); return 0; } #define VARTYPE_VAR 0x80 #define VARTYPE_BLOCK 0x40 #define VARTYPE_WORD 0x20 #define VARTYPE_KIND 0x1F #define VARSIZE_BYTE 0 #define VARSIZE_WORD 1 unsigned char var_size; unsigned short LoadVar(unsigned char **ptr, unsigned char **varptr) { unsigned char vartype; unsigned char *varbase; unsigned short value = 0; var_size = VARSIZE_BYTE; vartype = *((*ptr)++); if (vartype & VARTYPE_VAR) { /*variable*/ unsigned char varoffs; varbase = (unsigned char *)script_vars[vartype & VARTYPE_KIND]; if (vartype & VARTYPE_BLOCK) { unsigned char *end; unsigned char index = *((*ptr)++); varbase = SeekToEntryW(varbase, index, &end); } varoffs = *((*ptr)++); #if 1 { int maxoffs = 0; switch (vartype & VARTYPE_KIND) { case ScrPool0_WordVars0: case ScrPool1_WordVars1: maxoffs = sizeof(script_word_vars); break; case ScrPool2_ByteVars: maxoffs = sizeof(script_byte_vars); break; case ScrPool3_CurrentItem: maxoffs = sizeof(item_t); break; case ScrPool4_ZoneSpots: maxoffs = RES_ZONES_MAX; break; case ScrPool5_Persons: maxoffs = sizeof(pers_list); break; case ScrPool6_Inventory: maxoffs = sizeof(inventory_items); break; case ScrPool7_Inventory38: maxoffs = sizeof(inventory_items) - sizeof(item_t) * 38; break; case ScrPool8_CurrentPers: maxoffs = sizeof(pers_t); break; } if (varoffs >= maxoffs) { printf("Scr var out of bounds @ %X (pool %d, ofs 0x%X, max 0x%X)\n", (unsigned int)(script_ptr - templ_data), vartype & VARTYPE_KIND, varoffs, maxoffs); PromptWait(); } } #endif value = varbase[varoffs]; if (vartype & VARTYPE_WORD) { value = (value << 8) | varbase[varoffs + 1]; var_size = VARSIZE_WORD; } *varptr = &varbase[varoffs]; #if 0 /*TODO: debug stuff, remove me*/ if (varoffs == 0x48) printf("Var 2.%X = %X\n", varoffs, value); #endif } else { /*immediate value*/ value = *((*ptr)++); if (vartype & VARTYPE_WORD) { value = (value << 8) | *((*ptr)++); var_size = VARSIZE_WORD; } *varptr = 0; } return value; } #define MATHOP_END 0x80 #define MATHOP_CMP 0x40 #define MATHOP_ADD 0x20 #define MATHOP_SUB 0x10 #define MATHOP_AND 0x08 #define MATHOP_OR 0x04 #define MATHOP_XOR 0x02 #define MATHOP_EQ 0x20 #define MATHOP_B 0x10 #define MATHOP_A 0x08 #define MATHOP_NEQ 0x04 #define MATHOP_LE 0x02 #define MATHOP_GE 0x01 unsigned short MathOp(unsigned char op, unsigned short op1, unsigned short op2) { if (op & MATHOP_CMP) { if (op & MATHOP_EQ) if (op1 == op2) return ~0; if (op & MATHOP_B) if (op1 < op2) return ~0; if (op & MATHOP_A) if (op1 > op2) return ~0; if (op & MATHOP_NEQ) if (op1 != op2) return ~0; if (op & MATHOP_LE) if ((signed short)op1 <= (signed short)op2) return ~0; if (op & MATHOP_GE) if ((signed short)op1 >= (signed short)op2) return ~0; return 0; } else { if (op & MATHOP_ADD) op1 += op2; if (op & MATHOP_SUB) op1 -= op2; if (op & MATHOP_AND) op1 &= op2; if (op & MATHOP_OR) op1 |= op2; if (op & MATHOP_XOR) op1 ^= op2; return op1; } } unsigned short MathExpr(unsigned char **ptr) { unsigned char op; unsigned short op1, op2; unsigned char *opptr; op1 = LoadVar(ptr, &opptr); while (((op = *((*ptr)++)) & MATHOP_END) == 0) { op2 = LoadVar(ptr, &opptr); op1 = MathOp(op, op1, op2); } return op1; } /* Math operations (assignment) on a variable */ unsigned int SCR_3B_MathExpr(void) { unsigned short op1, op2; unsigned char *opptr; script_ptr++; op1 = LoadVar(&script_ptr, &opptr); op2 = MathExpr(&script_ptr); if (var_size == VARSIZE_BYTE) *opptr = op2 & 255; else { opptr[0] = op2 >> 8; /*store in big-endian*/ opptr[1] = op2 & 255; } /*return op1;*/ /*previous value, never used?*/ return 0; } /*Jump to routine*/ unsigned int SCR_12_Chain(void) { script_ptr++; the_command = *script_ptr++; /*little-endian*/ the_command |= (*script_ptr++) << 8; script_ptr = GetScriptSubroutine(the_command - 1); return 0; } /* Absolute jump Jumping past current routine ends the script */ unsigned int SCR_33_Jump(void) { unsigned short offs; script_ptr++; offs = *script_ptr++; /*little-endian*/ offs |= (*script_ptr++) << 8; script_ptr = templ_data + offs; return 0; } /* Conditional jump (IF/ELSE block) */ unsigned int SCR_3C_CondExpr(void) { script_ptr++; if (MathExpr(&script_ptr)) { /*fall to IF block*/ script_ptr += 2; } else { /*branch to ELSE block*/ script_ptr -= 1; /*simulate opcode byte for Jump handler*/ return SCR_33_Jump(); } return 0; } /* Absolute subroutine call */ unsigned int SCR_34_Call(void) { unsigned short offs; script_ptr++; offs = *script_ptr++; /*little-endian*/ offs |= (*script_ptr++) << 8; *script_stack_ptr++ = script_ptr; *script_stack_ptr++ = script_end_ptr; script_ptr = templ_data + offs; return 0; } /* Return from script subroutine */ unsigned int SCR_35_Ret(void) { script_end_ptr = *(--script_stack_ptr); script_ptr = *(--script_stack_ptr); return 0; } /*Draw portrait, pushing it from left to right*/ unsigned int SCR_5_DrawPortraitLiftRight(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; /*TODO: use local args instead of globals*/ CGA_AnimLiftToRight(width, cur_image_pixels + width - 1, width, 1, height, CGA_SCREENBUFFER, CGA_CalcXY_p(x, y)); return 0; } /*Draw portrait, pushing it from right to left*/ unsigned int SCR_6_DrawPortraitLiftLeft(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; /*TODO: use local args instead of globals*/ CGA_AnimLiftToLeft(width, cur_image_pixels, width, 1, height, CGA_SCREENBUFFER, CGA_CalcXY_p(x + width - 1, y)); return 0; } /*Draw portrait, pushing it from top to bottom*/ unsigned int SCR_7_DrawPortraitLiftDown(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; /*TODO: use local args instead of globals*/ CGA_AnimLiftToDown(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, cur_image_offs); return 0; } /*Draw portrait, pushing it from bottom to top*/ unsigned int SCR_8_DrawPortraitLiftUp(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; /*TODO: use local args instead of globals*/ CGA_AnimLiftToUp(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, x, y + height - 1); return 0; } /*Draw portrait, no special effects*/ unsigned int SCR_9_DrawPortrait(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; CGA_BlitAndWait(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, cur_image_offs); return 0; } /*Draw screen pixels using 2-phase clockwise twist*/ void TwistDraw(unsigned char x, unsigned char y, unsigned char width, unsigned char height, unsigned char *source, unsigned char *target) { int i; unsigned int sx, ex, sy, ey, t; sx = x * 4; ex = x * 4 + width * 4 - 1; sy = y; ey = y + height - 1; for (i = 0; i < width * 4; i++) { CGA_TraceLine(sx, ex, sy, ey, source, target); WaitVBlank(); sx += 1; ex -= 1; } t = sx; sx = ex + 1; ex = t - 1; t = sy; sy = ey; ey = t; for (i = 0; i < height; i++) { CGA_TraceLine(sx, ex, sy, ey, source, target); WaitVBlank(); sy -= 1; ey += 1; } } /*Draw image with twist-effect*/ unsigned int SCR_B_DrawPortraitTwistEffect(void) { unsigned char x, y, width, height; unsigned int offs; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; offs = CGA_CalcXY_p(x, y); CGA_SwapScreenRect(cur_image_pixels, width, height, backbuffer, offs); TwistDraw(x, y, width, height, backbuffer, frontbuffer); CGA_BlitAndWait(scratch_mem2, width, width, height, backbuffer, offs); return 0; } /*Draw screen pixels using arc-like sweep*/ void ArcDraw(unsigned char x, unsigned char y, unsigned char width, unsigned char height, unsigned char *source, unsigned char *target) { int i; unsigned int sx, ex, sy, ey; sx = x * 4; ex = x * 4 + width * 2 - 1; sy = y + height - 1; ey = y + height - 1; for (i = 0; i < height; i++) { CGA_TraceLine(sx, ex, sy, ey, source, target); WaitVBlank(); sy -= 1; } for (i = 0; i < width * 4; i++) { CGA_TraceLine(sx, ex, sy, ey, source, target); WaitVBlank(); sx += 1; } for (i = 0; i < height + 1; i++) { CGA_TraceLine(sx, ex, sy, ey, source, target); WaitVBlank(); sy += 1; } } /*Draw image with arc-effect*/ unsigned int SCR_C_DrawPortraitArcEffect(void) { unsigned char x, y, width, height; unsigned int offs; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; offs = CGA_CalcXY_p(x, y); CGA_SwapScreenRect(cur_image_pixels, width, height, backbuffer, offs); ArcDraw(x, y, width, height, backbuffer, frontbuffer); CGA_BlitAndWait(scratch_mem2, width, width, height, backbuffer, offs); return 0; } /*Draw image with slow top-to-down reveal effect by repeatedly draw its every 17th pixel*/ unsigned int SCR_D_DrawPortraitDotEffect(void) { int i; unsigned char x, y, width, height; unsigned int offs, step = 17; unsigned char *target = CGA_SCREENBUFFER; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; cur_image_end = width * height; for (offs = 0; offs != cur_image_end;) { target[CGA_CalcXY_p(x + offs % cur_image_size_w, y + offs / cur_image_size_w)] = cur_image_pixels[offs]; for (i = 0; i < 255; i++) ; /*TODO FIXME weak delay*/ offs += step; if (offs > cur_image_end) offs -= cur_image_end; } return 0; } /*Draw image with slow zoom-in reveal effect*/ unsigned int SCR_E_DrawPortraitZoomIn(void) { unsigned char x, y, width, height; script_ptr++; if (!DrawPortrait(&script_ptr, &x, &y, &width, &height)) return 0; /*TODO*/ CGA_BlitAndWait(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, cur_image_offs); return 0; } /*Hide portrait, pushing it from right to left*/ unsigned int SCR_19_HidePortraitLiftLeft(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } /*TODO: This originally was done by reusing door sliding routine*/ /*offs = CGA_CalcXY_p(x + 1, y);*/ offs++; while (--width) { CGA_HideScreenBlockLiftToLeft(1, CGA_SCREENBUFFER, backbuffer, width, height, CGA_SCREENBUFFER, offs); } offs--; /*hide leftmost line*/ /*TODO: move this to CGA?*/ while (height--) { memcpy(frontbuffer + offs, backbuffer + offs, 1); offs ^= CGA_ODD_LINES_OFS; if ((offs & CGA_ODD_LINES_OFS) == 0) offs += CGA_BYTES_PER_LINE; } return 0; } /*Hide portrait, pushing it from left to right*/ unsigned int SCR_1A_HidePortraitLiftRight(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } /*TODO: This originally was done by reusing door sliding routine*/ offs = CGA_CalcXY_p(x + width - 2, y); while (--width) { CGA_HideScreenBlockLiftToRight(1, CGA_SCREENBUFFER, backbuffer, width, height, CGA_SCREENBUFFER, offs); } offs++; /*hide leftmost line*/ /*TODO: move this to CGA?*/ while (height--) { memcpy(frontbuffer + offs, backbuffer + offs, 1); offs ^= CGA_ODD_LINES_OFS; if ((offs & CGA_ODD_LINES_OFS) == 0) offs += CGA_BYTES_PER_LINE; } return 0; } /*Hide portrait, pushing it from bottom to top*/ unsigned int SCR_1B_HidePortraitLiftUp(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } offs = CGA_CalcXY_p(x, y + 1); while (--height) { CGA_HideScreenBlockLiftToUp(1, CGA_SCREENBUFFER, backbuffer, width, height, CGA_SCREENBUFFER, offs); } /*hide topmost line*/ /*TODO: move this to CGA?*/ offs ^= CGA_ODD_LINES_OFS; if ((offs & CGA_ODD_LINES_OFS) != 0) offs -= CGA_BYTES_PER_LINE; memcpy(CGA_SCREENBUFFER + offs, backbuffer + offs, width); return 0; } /*Hide portrait, pushing it from top to bottom*/ unsigned int SCR_1C_HidePortraitLiftDown(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } offs = CGA_CalcXY_p(x, y + height - 2); while (--height) { CGA_HideScreenBlockLiftToDown(1, CGA_SCREENBUFFER, backbuffer, width, height, CGA_SCREENBUFFER, offs); } /*hide bottommost line*/ /*TODO: move this to CGA?*/ offs ^= CGA_ODD_LINES_OFS; if ((offs & CGA_ODD_LINES_OFS) == 0) offs += CGA_BYTES_PER_LINE; memcpy(CGA_SCREENBUFFER + offs, backbuffer + offs, width); return 0; } /*Hide portrait with twist effect*/ unsigned int SCR_1E_HidePortraitTwist(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } TwistDraw(x, y, width, height, backbuffer, frontbuffer); return 0; } /*Hide portrait with arc effect*/ unsigned int SCR_1F_HidePortraitArc(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } ArcDraw(x, y, width, height, backbuffer, frontbuffer); return 0; } /*Hide portrait with dots effect*/ unsigned int SCR_20_HidePortraitDots(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } dot_effect_step = 17; dot_effect_delay = 100; CopyScreenBlockWithDotEffect(backbuffer, x, y, width, height, frontbuffer); return 0; } unsigned int SCR_39_AnimRoomDoorOpen(void) { unsigned char door; script_ptr++; door = *script_ptr++; AnimRoomDoorOpen(door); return 0; } unsigned int SCR_3A_AnimRoomDoorClose(void) { unsigned char door; script_ptr++; door = *script_ptr++; AnimRoomDoorClose(door); return 0; } unsigned int SCR_25_ChangeZoneOnly(void) { unsigned char index; unsigned char old = script_byte_vars.zone_room; script_ptr++; index = *script_ptr++; ChangeZone(index); script_byte_vars.zone_room = old; return 0; } void JaggedZoom(void) { /*TODO*/ } void InitStarfield(void) { /*TODO*/ } void AnimStarfield(void) { /*TODO*/ } unsigned int SCR_26_GameOver(void) { in_de_profundis = 0; script_byte_vars.game_paused = 1; memset(backbuffer, 0, sizeof(backbuffer) - 2); /*TODO: original bug?*/ JaggedZoom(); CGA_BackBufferToRealFull(); CGA_ColorSelect(0x30); InitStarfield(); AnimStarfield(); PlayAnim(44, 156 / 4, 95); script_byte_vars.zone_index = 135; JaggedZoom(); CGA_BackBufferToRealFull(); /*RestartGame();*/ /*TODO: this should shomehow abort all current scripts/calls and restart the game*/ TODO("Restart"); return 0; } unsigned int SCR_4C_DrawZoneObjs(void) { script_ptr++; DrawZoneObjs(); return 0; } unsigned int SCR_13_RedrawRoomStatics(void) { unsigned char index; script_ptr++; index = *script_ptr++; RedrawRoomStatics(index, 0); return 0; } /* Load and draw zone (to backbuffer) */ unsigned int SCR_42_LoadZone(void) { unsigned char index; script_ptr++; index = *script_ptr++; zone_drawn = 0; if (right_button) script_byte_vars.byte_179B8 = 0; else { if ((script_byte_vars.cur_spot_flags & (SPOTFLG_20 | SPOTFLG_10 | SPOTFLG_8)) == 0) script_byte_vars.byte_179B8 = script_byte_vars.cur_spot_flags & 7; else if ((script_byte_vars.cur_spot_flags & ((SPOTFLG_20 | SPOTFLG_10 | SPOTFLG_8))) == SPOTFLG_8) { zone_drawn = 1; AnimRoomDoorOpen(script_byte_vars.cur_spot_idx); script_byte_vars.byte_179B8 = script_byte_vars.cur_spot_flags & 7; } else script_byte_vars.byte_179B8 = 0; } UpdateZoneSpot(index); ChangeZone(index); script_byte_vars.zone_area_copy = script_byte_vars.zone_area; script_byte_vars.cur_spot_idx = FindInitialSpot(); zone_drawn |= script_byte_vars.cur_spot_idx; DrawRoomStatics(); if (script_byte_vars.byte_17A15 != 0) { RedrawRoomStatics(script_byte_vars.byte_17A15, 0); script_byte_vars.byte_17A15 = 0; } BackupSpotsImages(); PrepareCommand3(); PrepareCommand4(); PrepareCommand1(); DrawZoneObjs(); script_byte_vars.cur_spot_flags = 0; return 0; } unsigned int SCR_59_BlitSpritesToBackBuffer(void) { script_ptr++; BlitSpritesToBackBuffer(); return 0; } unsigned int SCR_5A_SelectPalette(void) { script_ptr++; SelectPalette(); return 0; } unsigned int SCR_43_RefreshZone(void) { script_ptr++; RefreshZone(); return 0; } unsigned int SCR_36_ChangeZone(void) { SCR_42_LoadZone(); RefreshZone(); return 0; } void SCR_DrawRoomObjectBack(unsigned char *x, unsigned char *y, unsigned char *w, unsigned char *h) { unsigned char obj[3]; script_ptr++; obj[0] = *script_ptr++; /*spr*/ obj[1] = *script_ptr++; /*x*/ obj[2] = *script_ptr++; /*y*/ DrawRoomStaticObject(obj, x, y, w, h); } unsigned int SCR_5F_DrawRoomObjectBack(void) { unsigned char x, y, w, h; SCR_DrawRoomObjectBack(&x, &y, &w, &h); return 0; } unsigned int SCR_11_DrawRoomObject(void) { unsigned char x, y, w, h; SCR_DrawRoomObjectBack(&x, &y, &w, &h); CGA_CopyScreenBlock(backbuffer, w, h, CGA_SCREENBUFFER, CGA_CalcXY_p(x, y)); return 0; } /* Draw box with item sprite and its name */ unsigned int SCR_3_DrawItemBox(void) { unsigned char current; item_t *item; unsigned char x, y; unsigned char *msg; script_ptr++; current = *script_ptr++; if (current) item = (item_t *)script_vars[ScrPool3_CurrentItem]; else item = &inventory_items[pers_ptr->item - 1]; x = dirty_rects[0].x; y = dirty_rects[0].y + 70; msg = SeekToString(desci_data, 274 + item->name); DesciTextBox(x, y, 18, msg); DrawSpriteN(item->sprite, x, y + 1, CGA_SCREENBUFFER); return 0; } /*Draw simple bubble with text*/ unsigned int SCR_37_DesciTextBox(void) { unsigned char x, y, w; unsigned char *msg; script_ptr++; msg = SeekToStringScr(desci_data, *script_ptr, &script_ptr); script_ptr++; x = *script_ptr++; y = *script_ptr++; w = *script_ptr++; DesciTextBox(x, y, w, msg); return 0; } /*Play portrait animation*/ unsigned int SCR_18_AnimPortrait(void) { unsigned char layer, index, delay; script_ptr++; layer = *script_ptr++; index = *script_ptr++; delay = *script_ptr++; AnimPortrait(layer, index, delay); return 0; } /*Play animation*/ unsigned int SCR_38_PlayAnim(void) { unsigned char index, x, y; script_ptr++; index = *script_ptr++; x = *script_ptr++; y = *script_ptr++; PlayAnim(index, x, y); return 0; } /*Pop up the actions menu and handle its commands*/ unsigned int SCR_3D_ActionsMenu(void) { unsigned short cmd; unsigned char *old_script = script_ptr; unsigned char *old_script_end = script_end_ptr; act_menu_x = 0xFF; for (;;) { script_ptr++; ActionsMenu(&script_ptr); if (the_command == 0xFFFF) break; cmd = the_command & 0xF000; if (cmd == 0xC000 || cmd == 0xA000) { return ScriptRerun; } RunCommand(); script_byte_vars.used_commands++; if (script_byte_vars.byte_179F9 == 0 && script_byte_vars.check_used_commands < script_byte_vars.used_commands) { the_command = Swap16(script_word_vars.next_command1); if (the_command) return ScriptRerun; } script_ptr = old_script; if (--script_byte_vars.tries_left == 0) ResetAllPersons(); } script_end_ptr = old_script_end; return ScriptContinue; } /*The Wall room puzzle*/ unsigned int SCR_3E_TheWallAdvance(void) { script_ptr++; script_byte_vars.the_wall_phase = (script_byte_vars.the_wall_phase + 1) % 4; switch (script_byte_vars.the_wall_phase) { default: TheWallPhase3(); break; case 0: TheWallPhase0(); break; case 1: TheWallPhase1_DoorClose1(); break; case 2: TheWallPhase2_DoorClose2(); break; } return 0; } /* When playing cups with proto */ unsigned int SCR_28_MenuLoop(void) { unsigned char cursor; unsigned char mask, value; script_ptr++; cursor = *script_ptr++; mask = *script_ptr++; value = *script_ptr++; SelectCursor(cursor); MenuLoop(mask, value); return 0; } /* Restore screen data from back buffer as specified by dirty rects of specified index */ unsigned int SCR_2A_PopDialogRect(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); /*TODO: implicit target*/ CGA_CopyScreenBlock(backbuffer, 2, 21, CGA_SCREENBUFFER, offs = (x << 8) | y); /*TODO: implicit target*/ cur_dlg_index = 0; return 0; } /* Restore screen data from back buffer as specified by dirty rect of kind dialog bubble */ unsigned int SCR_2B_PopAllBubbles(void) { script_ptr++; PopDirtyRects(DirtyRectBubble); return 0; } /* Hide a portrait, with shatter effect */ unsigned int SCR_22_HidePortraitShatter(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } CGA_HideShatterFall(CGA_SCREENBUFFER, backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } /* Hide a portrait, no special effects */ unsigned int SCR_23_HidePortrait(void) { unsigned char index; unsigned char kind; unsigned char x, y; unsigned char width, height; unsigned int offs; script_ptr++; index = *script_ptr++; GetDirtyRectAndFree(index, &kind, &x, &y, &width, &height, &offs); if (right_button) { CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); return 0; } /* Restore screen data from back buffer for all portraits */ unsigned int SCR_24_PopAllPortraits(void) { script_ptr++; PopDirtyRects(DirtyRectSprite); return 0; } /* Restore screen data from back buffer for all text bubbles */ unsigned int SCR_40_PopAllTextBoxes() { script_ptr++; PopDirtyRects(DirtyRectText); return 0; } /* Move a Hand in Who Will Be Saved */ unsigned int SCR_41_LiftHand(void) { script_ptr++; RedrawRoomStatics(92, script_byte_vars.byte_179E1); CGA_BackBufferToRealFull(); PlaySound(31); return 0; } unsigned char fight_mode = 0; unsigned int SCR_30_Fight(void) { static unsigned char player_image[] = {26, 0, 0}; unsigned char *image = player_image; unsigned char x, y, width, height, kind; unsigned int offs; unsigned char *old_script, *old_script_end = script_end_ptr; pers_t *pers = (pers_t *)(script_vars[ScrPool8_CurrentPers]); unsigned char strenght, win, rnd; script_ptr++; old_script = script_ptr; x = 140 / 4; y = 20; fight_mode = 1; if (pers->name != 44) { if (next_command3 == 0xA015) { the_command = 0xA015; RunCommand(); FindAndSelectSpot((pers - pers_list) * 5); /*TODO: FindAndSelectSpot assumes plain offset, 5-byte records*/ } if (Swap16(script_word_vars.next_command1) == 0xC357) { the_command = 0xC357; RunCommand(); } pers = (pers_t *)(script_vars[ScrPool8_CurrentPers]); if (pers->name != 56 && pers->name != 51) { x = dirty_rects[0].x + 64 / 4; y = dirty_rects[0].y; fight_mode = 0; } } /*draw player portrait*/ player_image[1] = x; player_image[2] = y; if (DrawPortrait(&image, &x, &y, &width, &height)) CGA_AnimLiftToLeft(width, cur_image_pixels, width, 1, height, CGA_SCREENBUFFER, CGA_CalcXY_p(x + width - 1, y)); BlinkToWhite(); if (pers->name != 44 && pers->name != 56 && pers->name != 51) { GetDirtyRectAndFree(1, &kind, &x, &y, &width, &height, &offs); CGA_CopyScreenBlock(backbuffer, width, height, CGA_SCREENBUFFER, offs); } /*check fight outcome*/ strenght = 0; script_byte_vars.byte_179F2 = 0; if (script_byte_vars.byte_179F3 == 0) { static unsigned char character_strenght[] = {1, 3, 1, 1, 1, 1, 5, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1}; strenght = character_strenght[pers->name - 42]; /*check if can decrease*/ if (strenght != 1 && (pers->flags & PERSFLG_80)) strenght--; if (script_byte_vars.room_items != 0 || script_byte_vars.byte_17A1C != 0) strenght--; } /*check if can increase*/ if (strenght != 5) { if ((pers->item >= 19 && pers->item < 23) || (pers->item >= 39 && pers->item < 52) || pers->item == 56 || pers->item == 57 || ((pers->index >> 3) == 6)) strenght++; } win = 1; rnd = script_byte_vars.rand_value; #ifdef CHEAT strenght = 1; #endif if (strenght >= 2) { if (strenght == 2) { if (rnd >= 205) win = Rand() < 128 ? 81 : 82; } else if (strenght == 4 && rnd < 100) { win = Rand() < 128 ? 81 : 82; } else { win = 2; if (strenght == 3) { if (rnd < 128) /*TODO: check me, maybe original bug (checks against wrong reg?)*/ win = Rand() < 51 ? 145 : 146; else win = Rand() < 205 ? 49 : 50; } } } script_byte_vars.byte_179F2 = win; script_ptr = old_script; script_end_ptr = old_script_end; return 0; } unsigned char prev_fight_mode = 0; unsigned short fight_pers_ofs = 0; typedef struct fightentry_t { unsigned char room; animdesc_t anim; } fightentry_t; fightentry_t fightlist1[] = { {50, {47, 36, 153}}, {51, {47, 36, 153}}, {53, {47, 37, 160}}, {54, {47, 36, 153}}, {56, {47, 31, 128}}, {57, {47, 27, 161}}, {58, {47, 28, 152}}, {59, {47, 25, 153}}, {60, {47, 22, 155}}, {61, {47, 27, 160}} }; fightentry_t fightlist2[] = { { 1, {24, 42, 128}}, { 2, {24, 44, 126}}, { 3, {24, 47, 126}}, { 4, {24, 44, 126}}, { 5, {24, 47, 126}}, { 6, {24, 28, 126}}, { 7, {24, 55, 126}}, { 8, {24, 49, 126}}, {10, {24, 41, 147}}, {11, {24, 41, 147}}, {18, {24, 41, 147}}, {19, {24, 41, 147}}, {90, {24, 44, 121}}, {91, {28, 24, 123}}, {12, {24, 41, 147}}, {13, {24, 41, 147}}, {35, {24, 39, 147}}, {42, {24, 39, 147}}, {50, {55, 46, 130}}, {52, {24, 42, 121}}, {54, {55, 46, 130}}, {61, {67, 37, 125}}, {62, {55, 32, 133}}, {63, {55, 32, 133}}, {64, {55, 32, 133}}, {65, {55, 32, 133}} }; fightentry_t fightlist3[] = { { 2, {25, 35, 144}}, { 3, {25, 38, 144}}, { 4, {25, 35, 144}}, { 5, {25, 38, 144}}, { 6, {25, 19, 144}}, { 7, {25, 46, 144}}, { 8, {26, 64, 132}}, {10, {25, 32, 165}}, {11, {25, 32, 165}}, {12, {25, 32, 165}}, {13, {25, 32, 165}}, {18, {25, 32, 165}}, {19, {25, 32, 165}}, {90, {36, 27, 127}}, {91, {27, 44, 123}}, {35, {25, 30, 165}}, {42, {25, 30, 165}}, {50, {56, 36, 153}}, {54, {56, 36, 153}}, {62, {56, 22, 156}}, {63, {56, 22, 156}}, {64, {56, 22, 156}}, {65, {56, 22, 156}} }; /*Draw defeated enemy*/ unsigned int SCR_31_Fight2(void) { script_ptr++; if (script_byte_vars.byte_179F9 != 18) { pers_t *pers = (pers_t *)(script_vars[ScrPool8_CurrentPers]); fight_pers_ofs = (unsigned char *)pers - (unsigned char *)pers_list; /*TODO check size*/ pers->flags |= PERSFLG_40; pers->area = 0; found_spot->flags &= ~SPOTFLG_80; if (pers->index == 16) { pers_list[34].area = script_byte_vars.zone_area; pers_list[34].flags = pers->flags; if (script_byte_vars.room_items == 0) { static const animdesc_t anim19 = {ANIMFLG_USESPOT | 19}; AnimateSpot(&anim19); } the_command = next_command3; RunCommand(); } else if (pers->index == 8) { pers_list[35].area = script_byte_vars.zone_area; pers_list[35].flags = pers->flags; if (script_byte_vars.room_items == 0) { static const animdesc_t anim20 = {ANIMFLG_USESPOT | 20}; AnimateSpot(&anim20); } the_command = next_command3; RunCommand(); } else { if (prev_fight_mode == 0 && script_byte_vars.room_items != 0 && fight_mode == 0) { script_byte_vars.byte_179F2 &= ~1; } else { unsigned int i; fightentry_t *fightlist; unsigned int fightlistsize; unsigned char animidx; prev_fight_mode = 0; switch (pers->name) { case 56: animidx = 47; fightlist = fightlist1; fightlistsize = 10; break; case 51: next_command4 = 0; animidx = 66; fightlist = fightlist1; fightlistsize = 10; break; default: animidx = 0; fightlist = fightlist3; fightlistsize = 26; } for (i = 0; i < fightlistsize; i++) { if (fightlist[i].room == script_byte_vars.zone_room) { if (animidx != 0) fightlist[i].anim.index = animidx; if (fightlist[i].anim.index == 55) PlaySound(151); PlayAnim(fightlist[i].anim.index, fightlist[i].anim.params.coords.x, fightlist[i].anim.params.coords.y); break; } } } } } return 0; } unsigned int SCR_32_FightWin(void) { script_ptr++; script_byte_vars.byte_17A1D = 0; if (script_byte_vars.byte_179F9 != 18 && *spot_sprite != 0) { CGA_RestoreImage(*spot_sprite, frontbuffer); CGA_RestoreImage(*spot_sprite, backbuffer); if (script_byte_vars.byte_179F3 == 0 && script_byte_vars.byte_17A16 == 0 && script_byte_vars.room_items != 0 && fight_mode == 0) { script_byte_vars.byte_17A1D = 1; PlaySound(149); PlayAnim(40, found_spot->sx, found_spot->sy); } } prev_fight_mode = script_byte_vars.byte_179F3; script_byte_vars.byte_179F3 = 0; return 0; } extern void ExitGame(void); unsigned int SCR_15_SelectSpot(void) { unsigned char mask, index; script_ptr++; mask = *script_ptr++; index = *script_ptr++; if (mask != 0) { index = FindSpotByFlags(mask, index); /*TODO: return 0 if not found?*/ if (index == 0xFF) { TODO("ERROR: SelectSpot: spot not found"); ExitGame(); /*hard abort*/ } } found_spot = &zone_spots[index - 1]; script_byte_vars.cur_spot_idx = index; spot_sprite = &sprites_list[index - 1]; FindPerson(); if (script_byte_vars.cur_pers == 0) script_vars[ScrPool8_CurrentPers] = &pers_list[20]; return 0; } unsigned int SCR_44_BackBufferToScreen(void) { script_ptr++; CGA_BackBufferToRealFull(); return 0; } /* Animate De Profundis room on entry */ unsigned int SCR_45_DeProfundisRoomEntry(void) { unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Platform*/ sprofs = GetPuzzlSprite(3, 140 / 4, 174, &w, &h, &ofs); CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); /*draw Granite Monster*/ sprofs = GetPuzzlSprite(119, 128 / 4, 94, &w, &h, &ofs); CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); PromptWait(); for (; h; h--) { WaitVBlank(); WaitVBlank(); CGA_BlitFromBackBuffer(w, 1, CGA_SCREENBUFFER, ofs); ofs ^= CGA_ODD_LINES_OFS; if ((ofs & CGA_ODD_LINES_OFS) == 0) ofs += CGA_BYTES_PER_LINE; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } CGA_BlitFromBackBuffer(w, 1, CGA_SCREENBUFFER, ofs); return 0; } /* Animate De Profundis hook (lower) */ unsigned int SCR_46_DeProfundisLowerHook(void) { unsigned char y; unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Hook*/ sprofs = GetPuzzlSprite(96, 140 / 4, 18, &w, &h, &ofs); h = 1; y = 15; sprofs = y * 20 / 4 * 2; /*TODO: 20 is the sprite width. replace with w?*/ for (; y; y--) { WaitVBlank(); CGA_BlitFromBackBuffer(w, h, CGA_SCREENBUFFER, ofs); h++; sprofs -= 20 / 4 * 2; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } return 0; } /* Animate De Profundis monster (rise) */ unsigned int SCR_47_DeProfundisRiseMonster(void) { unsigned char y; unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Granite Monster head*/ sprofs = GetPuzzlSprite(118, 112 / 4, 174, &w, &h, &ofs); h = 1; y = 68; for (; y; y--) { WaitVBlank(); ofs ^= CGA_ODD_LINES_OFS; if ((ofs & CGA_ODD_LINES_OFS) != 0) ofs -= CGA_BYTES_PER_LINE; h++; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } return 0; } /* Animate De Profundis monster (lower) */ unsigned int SCR_48_DeProfundisLowerMonster(void) { unsigned char y; unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Hook*/ sprofs = GetPuzzlSprite(118, 112 / 4, 106, &w, &h, &ofs); y = 34; for (; y; y--) { WaitVBlank(); CGA_BlitFromBackBuffer(w, 1, CGA_SCREENBUFFER, ofs); ofs ^= CGA_ODD_LINES_OFS; if ((ofs & CGA_ODD_LINES_OFS) == 0) ofs += CGA_BYTES_PER_LINE; h--; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } return 0; } /* Animate De Profundis hook (rise) */ unsigned int SCR_49_DeProfundisRiseHook(void) { unsigned char y; unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Hook*/ sprofs = GetPuzzlSprite(96, 140 / 4, 18, &w, &h, &ofs); h = 16; y = 15; for (; y; y--) { WaitVBlank(); CGA_BlitFromBackBuffer(w, h, CGA_SCREENBUFFER, ofs); h--; sprofs += 20 / 4 * 2; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } CGA_BlitFromBackBuffer(w, 1, CGA_SCREENBUFFER, ofs); return 0; } /* Animate De Profundis platform */ unsigned int SCR_65_DeProfundisMovePlatform(void) { unsigned char state; unsigned char x, y; unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; state = *script_ptr++; x = 140 / 4; y = 174; if (state != 0) y += 4; /*draw Platform*/ sprofs = GetPuzzlSprite(3, x, y, &w, &h, &ofs); y = 4; if (state) { h -= 4; y--; } for (; y; y--) { WaitVBlank(); CGA_BlitFromBackBuffer(w, h, CGA_SCREENBUFFER, ofs); ofs ^= CGA_ODD_LINES_OFS; if ((ofs & CGA_ODD_LINES_OFS) == 0) ofs += CGA_BYTES_PER_LINE; h--; CGA_BlitScratchBackSprite(sprofs, w, h, CGA_SCREENBUFFER, ofs); } if (state) CGA_BlitFromBackBuffer(w, h, CGA_SCREENBUFFER, ofs); return 0; } /* Animate De Profundis monster ride to exit door */ unsigned int SCR_66_DeProfundisRideToExit(void) { unsigned int w, h; unsigned int sprofs, ofs; script_ptr++; /*draw Granite Monster*/ sprofs = GetPuzzlSprite(119, 128 / 4, 139, &w, &h, &ofs); CGA_BlitScratchBackSprite(sprofs, w, 20, backbuffer, ofs); dot_effect_delay = 1; dot_effect_step = 17; CopyScreenBlockWithDotEffect(backbuffer, 112 / 4, 139, 72 / 4, 40, frontbuffer); return 0; } /* Draw item bounce to room objects animation */ unsigned int SCR_4E_BounceCurrentItemToRoom(void) { script_ptr++; BounceCurrentItem(ITEMFLG_40, 43); return 0; } /* Draw item bounce to inventory animation */ unsigned int SCR_4F_BounceCurrentItemToInventory(void) { script_ptr++; BounceCurrentItem(ITEMFLG_80, 85); return 0; } /* Draw item bounce to inventory animation */ unsigned int SCR_50_BounceItemToInventory(void) { unsigned char itemidx; script_ptr++; itemidx = *script_ptr++; script_vars[ScrPool3_CurrentItem] = &inventory_items[itemidx - 1]; BounceCurrentItem(ITEMFLG_80, 85); return 0; } unsigned int SCR_51_ItemTrade(void) { unsigned char *old_script, *old_script_end = script_end_ptr; unsigned char status; if (script_byte_vars.byte_179DC >= 63) /*TODO: hang?*/ return 0; script_ptr++; old_script = script_ptr; inv_bgcolor = 0xFF; OpenInventory(0xFF, ITEMFLG_80); status = 1; if (inv_count != 0) { status = 2; if (the_command != 0) { status = 3; if (script_byte_vars.inv_item_index >= 6 && script_byte_vars.inv_item_index < 27) { the_command = 0xC204; RunCommand(); ((item_t *)(script_vars[ScrPool3_CurrentItem]))->flags = 0; OpenInventory(0xFF, ITEMFLG_10); status = 4; if (the_command != 0) { status = 5; if (script_byte_vars.rand_value < 128) { status = 6; ((item_t *)(script_vars[ScrPool3_CurrentItem]))[-1].flags = ITEMFLG_10; /*TODO: what's up with this index?*/ ((item_t *)(script_vars[ScrPool3_CurrentItem]))->flags = 0; } } } } } script_byte_vars.trade_status = status; script_ptr = old_script; script_end_ptr = old_script_end; return 0; } unsigned int SCR_52_RefreshSpritesData(void) { script_ptr++; RefreshSpritesData(); return 0; } unsigned int SCR_53_FindInvItem(void) { unsigned char first, count, flags, i; item_t *item; script_ptr++; first = *script_ptr++; count = *script_ptr++; flags = *script_ptr++; item = &inventory_items[first - 1]; for (i = 0; i < count; i++) { if (item[i].flags == flags) { script_vars[ScrPool3_CurrentItem] = &item[i]; return 0; } } script_vars[ScrPool3_CurrentItem] = &item[count - 1]; return 0; } unsigned int SCR_64_DrawBoxAroundSpot(void) { script_ptr++; DrawBoxAroundSpot(); return 0; } /* Draw text box */ unsigned int SCR_14_DrawDesc(void) { unsigned char *msg; script_ptr++; msg = SeekToStringScr(desci_data, *script_ptr, &script_ptr); script_ptr++; DrawMessage(msg, CGA_SCREENBUFFER); return 0; } /* Draw dialog bubble with text for a person, wait for a key, then hide. Auto find bubble location Use "thought" spike */ unsigned int SCR_17_DrawPersonThoughtBubbleDialog(void) { unsigned char x, y; unsigned char *msg; script_ptr++; msg = SeekToStringScr(diali_data, *script_ptr, &script_ptr); script_ptr++; x = found_spot->sx; y = found_spot->sy; if (x < 140 / 4) DrawPersonBubble(found_spot->ex, y - 40, SPIKE_BUBLEFT | 20, msg); else DrawPersonBubble(x - 80 / 4, y - 40, SPIKE_BUBRIGHT | 20, msg); PromptWait(); PopDirtyRects(DirtyRectBubble); return 0; } /* Draw dialog bubble with text for a person, wait for a key, then hide. Auto find bubble location Use normal spike */ unsigned int SCR_61_DrawPersonBubbleDialog(void) { unsigned char x, y; unsigned char *msg; script_ptr++; msg = SeekToStringScr(diali_data, *script_ptr, &script_ptr); script_ptr++; x = found_spot->sx; y = found_spot->sy; if (x < 140 / 4) DrawPersonBubble(found_spot->ex, y - 40, SPIKE_DNLEFT | 20, msg); else DrawPersonBubble(x - 80 / 4, y - 40, SPIKE_DNRIGHT | 20, msg); PromptWait(); PopDirtyRects(DirtyRectBubble); return 0; } #if 1 unsigned char *DebugString(char *msg, ...) { int i; unsigned char c; static unsigned char m[256]; va_list ap; va_start(ap, msg); vsprintf((char *)m, msg, ap); va_end(ap); for (i = 0; m[i]; i++) { c = m[i]; if (c >= 'A' && c <= 'Z') c = 0x21 + (c - 'A'); else if (c >= 'a' && c <= 'z') c = 0x21 + (c - 'a'); else if (c >= '0' && c <= '9') c = 0x10 + (c - '0'); else if (c == ' ') c = 0x20; else if (c == '!') c = 0x01; else if (c == ',') c = 0x0C; else if (c == '.') c = 0x0E; else if (c == '\n') c = 0x00; else c = 0x1F; m[i] = c; } cur_str_end = m + i; return m; } #endif /* Draw dialog bubble with text for gauss */ unsigned int SCR_27_DrawGaussBubble(void) { unsigned char *msg; script_ptr++; msg = SeekToStringScr(diali_data, *script_ptr, &script_ptr); script_ptr++; DrawPersonBubble(32 / 4, 20, 15, msg); return 0; } /* Draw dialog bubble with text */ unsigned int SCR_29_DialiTextBox(void) { unsigned char x, y, f; unsigned char *msg; script_ptr++; msg = SeekToStringScr(diali_data, *script_ptr, &script_ptr); cur_dlg_index = cur_str_index; /*TODO: useless?*/ script_ptr++; x = *script_ptr++; y = *script_ptr++; f = *script_ptr++; DrawPersonBubble(x, y, f, msg); return 0; } /* Do nothing in PC/CGA version */ unsigned int SCR_67_Unused(void) { script_ptr++; script_ptr++; return 0; } /* Do nothing in PC/CGA version */ unsigned int SCR_68_Unused(void) { script_ptr++; script_ptr++; return 0; } /* Play sound */ unsigned int SCR_69_PlaySound(void) { unsigned char index; script_ptr++; index = *script_ptr++; script_ptr++; PlaySound(index); return 0; } /* Do nothing in PC/CGA version */ unsigned int SCR_6A_Unused(void) { script_ptr++; return 0; } /* Open room's items inventory */ unsigned int CMD_1_RoomObjects(void) { UpdateUndrawCursor(CGA_SCREENBUFFER); inv_bgcolor = 0xAA; OpenInventory((0xFF << 8) | ITEMFLG_40, (script_byte_vars.zone_area << 8) | ITEMFLG_40); return ScriptRerun; } /* Open Psi Powers menu */ unsigned int CMD_2_PsiPowers(void) { /*Psi powers bar*/ BackupAndShowSprite(3, 280 / 4, 40); ProcessInput(); do { PollInput(); SelectCursor(CURSOR_0); CheckPsiCommandHover(); if (command_hint != 100) command_hint += 109; if (command_hint != last_command_hint) DrawCommandHint(); DrawHintsAndCursor(CGA_SCREENBUFFER); } while (buttons == 0); UndrawCursor(CGA_SCREENBUFFER); CGA_RestoreBackupImage(CGA_SCREENBUFFER); return ScriptRerun; } /* Open normal inventory box */ unsigned int CMD_3_Posessions(void) { UpdateUndrawCursor(CGA_SCREENBUFFER); inv_bgcolor = 0x55; OpenInventory(ITEMFLG_80, ITEMFLG_80); return ScriptRerun; } /* Show energy level */ unsigned int CMD_4_EnergyLevel(void) { static unsigned char energy_image[] = {130, 236 / 4, 71}; unsigned char x, y, width, height; unsigned char *image = energy_image; unsigned char anim = 40; PopDirtyRects(DirtyRectSprite); PopDirtyRects(DirtyRectBubble); if (script_byte_vars.psy_energy != 0) anim = 41 + (script_byte_vars.psy_energy / 16); if (DrawPortrait(&image, &x, &y, &width, &height)) { CGA_BlitAndWait(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, cur_image_offs); } do { AnimPortrait(1, anim, 10); AnimPortrait(1, anim + 14, 10); PollInput(); } while (buttons == 0); PopDirtyRects(DirtyRectSprite); return 0; } /* Advance time */ unsigned int CMD_5_Wait(void) { script_byte_vars.byte_179DB++; script_word_vars.timer_ticks2 = Swap16(Swap16(script_word_vars.timer_ticks2) + 300); the_command = next_command3; RunCommand(); the_command = next_command4; RunCommand(); script_byte_vars.used_commands = script_byte_vars.check_used_commands; the_command = Swap16(script_word_vars.word_17852); if (the_command == 0) { if (script_word_vars.next_command1 == 0) { the_command = 0x9005; RunCommand(); } } else { if (script_byte_vars.byte_179DC >= 63 && script_byte_vars.zone_area < 22 && script_byte_vars.zone_area != 1) the_command = 0x9005; return ScriptRerun; } return 0; } /* Load game (menu) */ unsigned int CMD_6_Load(void) { the_command = 0xC35C; return ScriptRerun; } /* Save game (menu) */ unsigned int CMD_7_Save(void) { the_command = 0xC35D; return ScriptRerun; } /* Show timer */ unsigned int CMD_8_Timer(void) { static unsigned char timer_image[] = {163, 244 / 4, 104}; unsigned char x, y, width, height; unsigned char *image = timer_image; if (DrawPortrait(&image, &x, &y, &width, &height)) { CGA_BlitAndWait(cur_image_pixels, cur_image_size_w, cur_image_size_w, cur_image_size_h, CGA_SCREENBUFFER, cur_image_offs); } do { unsigned short timer = Swap16(script_word_vars.timer_ticks2); unsigned short minutes = timer % (60 * 60); char_draw_coords_x = 260 / 4; char_draw_coords_y = 120; WaitVBlank(); CGA_PrintChar(timer / (60 * 60) + 16, CGA_SCREENBUFFER); CGA_PrintChar((minutes & 1) ? 26 : 0, CGA_SCREENBUFFER); /*colon*/ CGA_PrintChar(minutes / (60 * 10) + 16, CGA_SCREENBUFFER); CGA_PrintChar(minutes / 60 + 16, CGA_SCREENBUFFER); PollInput(); } while (buttons == 0); PopDirtyRects(DirtyRectSprite); return 0; } int ConsumePsiEnergy(unsigned char amount) { unsigned char current = script_byte_vars.psy_energy; if (current < amount) { /*no energy left*/ PlayAnim(68, 296 / 4, 71); return 0; } script_byte_vars.psy_energy = current - amount; /*significantly changed?*/ if ((current & 0xF0) != (script_byte_vars.psy_energy & 0xF0)) PlayAnim(68, 296 / 4, 71); return 1; } unsigned int CMD_A_PsiSolarEyes(void) { if (!ConsumePsiEnergy(2)) return 0; if (zone_palette == 14) { RedrawRoomStatics(script_byte_vars.zone_room, zone_palette); zone_palette = 0; CGA_BackBufferToRealFull(); } the_command = Swap16(script_word_vars.word_178EE); RunCommand(); script_byte_vars.cur_spot_flags = 0xFF; return 0; } unsigned short GetZoneObjCommand(unsigned int offs) { /*TODO: fix me: change offs/2 to index*/ the_command = Swap16(script_word_vars.zone_obj_cmds[(script_byte_vars.cur_spot_idx - 1) * 5 + offs / 2]); return the_command; } void DrawStickyNet(void) { unsigned char x, y, w, h; unsigned int ofs; unsigned char *sprite = LoadPuzzlToScratch(80); x = room_bounds_rect.sx; y = room_bounds_rect.sy; w = room_bounds_rect.ex - x; h = room_bounds_rect.ey - y; ofs = CGA_CalcXY_p(x, y); /*16x30 is the net sprite size*/ for (; h; h -= 30) { int i; for (i = 0; i < w; i += 16 / 4) DrawSprite(sprite, frontbuffer, ofs + i); ofs += CGA_BYTES_PER_LINE * 30 / 2; } } unsigned int CMD_B_PsiStickyFingers(void) { if (!ConsumePsiEnergy(3)) return 0; if (script_byte_vars.byte_179F9 != 0) { the_command = Swap16(script_word_vars.word_178F0); return ScriptRerun; } BackupScreenOfSpecialRoom(); DrawStickyNet(); SelectCursor(CURSOR_FLY); MenuLoop(0, 0); PlaySound(224); CGA_BackBufferToRealFull(); RestoreScreenOfSpecialRoom(); if (script_byte_vars.cur_spot_idx == 0 || GetZoneObjCommand(0) == 0) the_command = Swap16(script_word_vars.word_17844); if (script_byte_vars.byte_179DC >= 63 && script_byte_vars.zone_area < 22 && script_byte_vars.zone_area != 1) the_command = 0x9005; return ScriptRerun; } unsigned int CMD_C_PsiKnowMind(void) { if (!ConsumePsiEnergy(1)) return 0; if (script_byte_vars.byte_179F9 != 0) { the_command = Swap16(script_word_vars.word_178F2); return ScriptRerun; } ProcessMenu(); if (script_byte_vars.cur_spot_idx == 0 || GetZoneObjCommand(4) == 0) the_command = Swap16(script_word_vars.word_17846); return ScriptRerun; } unsigned int CMD_D_PsiBrainwarp(void) { if (!ConsumePsiEnergy(2)) return 0; if (script_byte_vars.byte_179F9 == 0) { BackupScreenOfSpecialRoom(); ProcessMenu(); if (script_byte_vars.cur_spot_idx == 0) { the_command = Swap16(script_word_vars.word_17850); script_byte_vars.dead_flag = 0; return ScriptRerun; } if (GetZoneObjCommand(2) != 0) { PlayAnim(39, found_spot->sx + 8 / 4, found_spot->sy - 10); RestoreScreenOfSpecialRoom(); return ScriptRerun; } } if (script_byte_vars.byte_179F9 == 18) { script_byte_vars.dead_flag = 1; script_byte_vars.tries_left = 2; return 0; } ((pers_t *)script_vars[ScrPool8_CurrentPers])->flags |= PERSFLG_80; script_byte_vars.dead_flag = script_byte_vars.cur_spot_idx; script_byte_vars.tries_left = 2; the_command = 0; if (script_byte_vars.byte_179F9 == 0) { PlayAnim(39, found_spot->sx + 8 / 4, found_spot->sy - 10); RestoreScreenOfSpecialRoom(); return ScriptRerun; } the_command = 0x90AA; return ScriptRerun; } unsigned int CMD_E_PsiZoneScan(void) { unsigned char x, y, w, h; unsigned int offs; if (!ConsumePsiEnergy(1)) return 0; if (script_byte_vars.byte_179F9 != 0) { the_command = Swap16(script_word_vars.word_178FC); return ScriptRerun; } BackupScreenOfSpecialRoom(); offs = CGA_CalcXY_p(room_bounds_rect.sx, room_bounds_rect.sy); w = room_bounds_rect.ex - room_bounds_rect.sx; h = room_bounds_rect.ey - room_bounds_rect.sy; for (y = room_bounds_rect.sy; h; y++, h--) { spot_t *spot; for (x = 0; x < w; x++) frontbuffer[offs + x] = ~frontbuffer[offs + x]; WaitVBlank(); for (x = 0; x < w; x++) frontbuffer[offs + x] = ~frontbuffer[offs + x]; for (spot = zone_spots; spot != zone_spots_end; spot++) { if ((spot->flags & ~(SPOTFLG_40 | 7)) == (SPOTFLG_20 | SPOTFLG_8) && spot->sy == y) { PlaySound(27); spot->flags |= SPOTFLG_80; PlayAnim(38, spot->sx, spot->sy); break; } } offs ^= CGA_ODD_LINES_OFS; if ((offs & CGA_ODD_LINES_OFS) == 0) offs += CGA_BYTES_PER_LINE; } RestoreScreenOfSpecialRoom(); the_command = Swap16(script_word_vars.word_17848); return ScriptRerun; } unsigned int CMD_F_PsiPsiShift(void) { if (!ConsumePsiEnergy(3)) return 0; if (script_byte_vars.byte_179F9 != 0) { the_command = Swap16(script_word_vars.word_178F4); return ScriptRerun; } SelectCursor(CURSOR_4); MenuLoop(0, 0); BackupScreenOfSpecialRoom(); PlaySound(25); PlayAnim(39, cursor_x / 4, cursor_y); RestoreScreenOfSpecialRoom(); if (script_byte_vars.cur_spot_idx == 0 || GetZoneObjCommand(6) == 0) the_command = Swap16(script_word_vars.word_1784E); return ScriptRerun; } unsigned int CMD_10_PsiExtremeViolence(void) { unsigned short command; if (!ConsumePsiEnergy(8)) return 0; script_byte_vars.byte_179F3 = 1; if (script_byte_vars.byte_179F9 != 0) { the_command = Swap16(script_word_vars.word_178F6); return ScriptRerun; } ProcessMenu(); if (script_byte_vars.cur_spot_idx == 0) { the_command = Swap16(script_word_vars.word_1784C); script_byte_vars.byte_179F3 = 0; return ScriptRerun; } command = GetZoneObjCommand(8); if ((command & 0xF000) == 0x9000) script_byte_vars.byte_179F3 = 0; else if (command == 0) { the_command = Swap16(script_word_vars.word_1784C); script_byte_vars.byte_179F3 = 0; } return ScriptRerun; } unsigned int CMD_11_PsiTuneIn(void) { unsigned short command; unsigned char *msg; if (!ConsumePsiEnergy(4)) return 0; if (script_byte_vars.byte_179F9 != 0) command = Swap16(script_word_vars.word_178F8); else { if (script_byte_vars.byte_179DC < 63 || script_byte_vars.zone_area >= 22) command = Swap16(script_word_vars.word_1784A); else command = 275; } /*TODO: is this really neccessary? Maybe it's always set when loaded from script vars?*/ if (command & 0x8000) { the_command = command; return ScriptRerun; } msg = SeekToString(diali_data, command); cur_dlg_index = cur_str_index; /*TODO: useless?*/ DrawPersonBubble(32 / 4, 20, 15, msg); PromptWait(); PopDirtyRects(DirtyRectBubble); return 0; } void ActionForPersonChoice(unsigned short *actions) { ProcessMenu(); the_command = 0x9183; /*THERE`S NOBODY.*/ if (script_byte_vars.cur_spot_idx != 0 && script_byte_vars.cur_pers != 0) { pers_t *pers = (pers_t *)script_vars[ScrPool8_CurrentPers]; unsigned char index = pers->name; if (index == 93) /*CADAVER*/ index = 19 + 42; else if (index == 133) /*SCI FI*/ index = 18 + 42; index -= 42; /*Person names: THE MASTER OF ORDEALS, etc*/ the_command = actions[index]; PlaySound(22); } } /*TODO: ensure these are never accessed/modified from the scripts*/ unsigned short menu_commands_12[] = { 0xC0F0, 0xC0D7, 0x9019, 0xC0DA, 0x9019, 0xC0F1, 0x9007, 0xC0D8, 0x9007, 0x9019, 0x9007, 0x9007, 0xC34E, 0xC34F, 0x9019, 0x9019, 0x9019, 0x9019, 0xC319, 0x9007 }; unsigned short menu_commands_22[] = { 0xC325, 0xC326, 0xC31B, 0xC31D, 0xC31F, 0xC31E, 0xC320, 0xC327, 0x90EC, 0xC31C, 0xC328, 0, 0xC077, 0xC077, 0xC321, 0xC322, 0x9007, 0xC323, 0xC2A7, 0xC324 }; unsigned short menu_commands_24[] = { 0xC344, 0xC34A, 0xC343, 0xC34D, 0x9019, 0xC0F1, 0x9007, 0xC354, 0x90EC, 0xC343, 0xC345, 0, 0xC343, 0xC343, 0xC343, 0x9019, 0x9019, 0x9019, 0xC343, 0xC343 }; unsigned short menu_commands_23[] = { 0xC002, 0xC32A, 0x9019, 0xC325, 0xC114, 0xC32B, 0xC32C, 0xC355, 0x90EC, 0x9019, 0xC328, 0, 0xC077, 0xC077, 0x9019, 0x9113, 0, 0xC323, 0xC2A7, 0xC32D }; unsigned int CMD_12_(void) { printf("cmd 12\n"); ActionForPersonChoice(menu_commands_12); return ScriptRerun; } unsigned int CMD_13_ActivateFountain(void) { static unsigned char water1[] = {125, 156 / 4, 58}; static unsigned char water2[] = {126, 156 / 4, 58}; static unsigned char headl[] = {88, 152 / 4, 52}; static unsigned char headr[] = {88, (160 / 4) | 0x80, 52}; unsigned char x, y, w, h; unsigned int i, j; script_byte_vars.byte_17A20 = 1; for (i = 0; i < 10; i++) { DrawRoomStaticObject(water1, &x, &y, &w, &h); WaitVBlank(); CGA_BackBufferToRealFull(); for (j = 0; j < 0x1FFF; j++) ; /*TODO: weak delay*/ DrawRoomStaticObject(water2, &x, &y, &w, &h); WaitVBlank(); CGA_BackBufferToRealFull(); for (j = 0; j < 0x1FFF; j++) ; /*TODO: weak delay*/ } DrawRoomStaticObject(headl, &x, &y, &w, &h); DrawRoomStaticObject(headr, &x, &y, &w, &h); CGA_BackBufferToRealFull(); return 0; } /*Vorts walking into the room*/ unsigned int CMD_14_VortAppear(void) { /*TODO: check me*/ pers_list[0].area = script_byte_vars.zone_area; FindAndSelectSpot(0); AnimateSpot(&vortanims_ptr->field_1); next_command3 = 0xA015; BlitSpritesToBackBuffer(); DrawZoneObjs(); CGA_BackBufferToRealFull(); next_ticks3 = Swap16(script_word_vars.timer_ticks2) + 5; return 0; } pers_t *pers_vort_ptr; struct { unsigned char room; unsigned char field_1; } vortleave[] = { { 2, 5}, { 3, 8}, { 4, 8}, { 5, 2}, {120, 3}, {121, 3}, { 8, 10}, { 10, 8}, { 60, 62}, { 62, 66}, { 68, 66}, { 69, 66}, { 67, 65}, { 65, 66}, { 70, 71}, { 71, 70}, { 59, 60}, { 60, 62}, { 63, 65} }; /*Vorts walking out of the room*/ unsigned int CMD_15_VortLeave(void) { /*TODO: check me*/ unsigned int i; animdesc_t *anim; pers_t *pers; if (pers_list[0].area != 0) { pers = &pers_list[0]; anim = &vortanims_ptr->field_4; } else if (pers_list[34].area != 0) { pers = &pers_list[34]; anim = &vortanims_ptr->field_7; } else { script_byte_vars.byte_179EC |= 0x80; pers_list[35].area = 0; pers_list[0].flags = pers_list[35].flags; pers = &pers_list[0]; anim = &vortanims_ptr->field_A; } pers->area = 0; next_command3 = 0; for (i = 0; i < 19; i++) { if (vortleave[i].room == script_byte_vars.zone_index) { next_command3 = 0xA016; next_ticks3 = Swap16(script_word_vars.timer_ticks2) + 5; pers->area = vortleave[i].field_1; } } pers_vort_ptr = pers; zone_spots[(pers->flags & 15) - 1].flags &= ~SPOTFLG_80; FindAndSelectSpot(0); AnimateSpot(anim); script_byte_vars.byte_179EC &= 0x80; return 0; } /* Vorts left the room */ unsigned int CMD_16_VortGone(void) { pers_vort_ptr->area = 0; next_command3 = 0; return 0; } unsigned int CMD_18_AspirantLeave(void) { /*TODO: check me*/ static const animdesc_t anim33 = {ANIMFLG_USESPOT | 33}; PopDirtyRects(DirtyRectSprite); PopDirtyRects(DirtyRectText); pers_ptr->area = 0; script_word_vars.next_command1 = BE(0); if ((pers_ptr->flags & PERSFLG_40) == 0) { spot_ptr->flags &= ~SPOTFLG_80; FindAndSelectSpot(script_byte_vars.quest_item_ofs); script_byte_vars.byte_179EF = 0; AnimateSpot(&anim33); } return 0; } /* Show Holo screen anim and speech */ unsigned int CMD_1B_Holo(void) { unsigned char x, y; unsigned int num; unsigned char *msg; x = found_spot->sx; y = found_spot->sy; PlayAnim(42, x + 4 / 4, y + 6); num = 321 + ((Swap16(script_word_vars.timer_ticks2) < 60 * 60) ? 0 : 4) + (script_byte_vars.rand_value % 4); msg = SeekToString(diali_data, num); cur_dlg_index = cur_str_index; /*TODO: useless?*/ if (x < 140 / 4) DrawPersonBubble(x + 32 / 4, y - 40, SPIKE_DNLEFT | 20, msg); else DrawPersonBubble(x - 92 / 4, y - 40, SPIKE_DNRIGHT | 20, msg); PlayAnim(43, x, y); PromptWait(); PopDirtyRects(DirtyRectBubble); PlayAnim(45, x, y); return 0; } /* TODO: check me */ unsigned int CMD_20_(void) { pers_list[5].area = 0; next_command4 = 0; return 0; } /* Talk to Vorts */ unsigned int CMD_21_VortTalk(void) { unsigned char x, y; unsigned int num; unsigned char *msg; if (script_byte_vars.rand_value >= 85) num = 6; else if (script_byte_vars.rand_value >= 170) num = 7; else num = 35; msg = SeekToString(diali_data, num); cur_dlg_index = cur_str_index; /*TODO: useless?*/ x = found_spot->sx; y = found_spot->sy; if (x < 140 / 4) DrawPersonBubble(found_spot->ex, y - 40, SPIKE_DNLEFT | 20, msg); else DrawPersonBubble(x - 80 / 4, y - 40, SPIKE_DNRIGHT | 20, msg); PromptWait(); PopDirtyRects(DirtyRectBubble); return 0; } unsigned int CMD_22_(void) { ActionForPersonChoice(menu_commands_22); return ScriptRerun; } unsigned int CMD_23_(void) { ActionForPersonChoice(menu_commands_23); return ScriptRerun; } unsigned int CMD_24_(void) { ActionForPersonChoice(menu_commands_24); return ScriptRerun; } unsigned int CMD_25_LoadGame(void) { if (LoadScena()) the_command = 0x918F; /*error loading*/ else the_command = 0x90AA; return ScriptRerun; } unsigned int CMD_26_SaveGame(void) { if (SaveScena()) the_command = 0x9190; /*error saving*/ else the_command = 0x90AA; return ScriptRerun; } typedef unsigned int (*cmdhandler_t)(void); cmdhandler_t command_handlers[] = { 0, CMD_1_RoomObjects, CMD_2_PsiPowers, CMD_3_Posessions, CMD_4_EnergyLevel, CMD_5_Wait, CMD_6_Load, CMD_7_Save, CMD_8_Timer, CMD_TRAP, CMD_A_PsiSolarEyes, CMD_B_PsiStickyFingers, CMD_C_PsiKnowMind, CMD_D_PsiBrainwarp, CMD_E_PsiZoneScan, CMD_F_PsiPsiShift, CMD_10_PsiExtremeViolence, /*10*/ CMD_11_PsiTuneIn, CMD_12_, CMD_13_ActivateFountain, CMD_14_VortAppear, CMD_15_VortLeave, CMD_16_VortGone, CMD_TRAP, CMD_18_AspirantLeave, CMD_TRAP, CMD_TRAP, CMD_1B_Holo, CMD_TRAP, CMD_TRAP, CMD_TRAP, CMD_TRAP, CMD_TRAP, /*20*/ CMD_21_VortTalk, CMD_22_, CMD_23_, CMD_24_, CMD_25_LoadGame, CMD_26_SaveGame }; #define MAX_CMD_HANDLERS (sizeof(command_handlers) / sizeof(command_handlers[0])) cmdhandler_t script_handlers[] = { 0, SCR_1_AspirantItemTrade, SCR_TRAP, SCR_3_DrawItemBox, SCR_TRAP, SCR_5_DrawPortraitLiftRight, SCR_6_DrawPortraitLiftLeft, SCR_7_DrawPortraitLiftDown, SCR_8_DrawPortraitLiftUp, SCR_9_DrawPortrait, SCR_TRAP, SCR_B_DrawPortraitTwistEffect, SCR_C_DrawPortraitArcEffect, SCR_D_DrawPortraitDotEffect, SCR_E_DrawPortraitZoomIn, SCR_TRAP, SCR_TRAP, /*10*/ SCR_11_DrawRoomObject, SCR_12_Chain, SCR_13_RedrawRoomStatics, SCR_14_DrawDesc, SCR_15_SelectSpot, SCR_TRAP, SCR_17_DrawPersonThoughtBubbleDialog, SCR_18_AnimPortrait, SCR_19_HidePortraitLiftLeft, SCR_1A_HidePortraitLiftRight, SCR_1B_HidePortraitLiftUp, SCR_1C_HidePortraitLiftDown, SCR_TRAP, /*TODO: same as SCR_23_HidePortrait , unused*/ SCR_1E_HidePortraitTwist, SCR_1F_HidePortraitArc, SCR_20_HidePortraitDots, /*20*/ SCR_TRAP, /*TODO: same as SCR_23_HidePortrait , unused*/ SCR_22_HidePortraitShatter, SCR_23_HidePortrait, SCR_24_PopAllPortraits, SCR_25_ChangeZoneOnly, SCR_26_GameOver, SCR_27_DrawGaussBubble, SCR_28_MenuLoop, SCR_29_DialiTextBox, SCR_2A_PopDialogRect, SCR_2B_PopAllBubbles, SCR_2C_Wait4, SCR_2D_Wait, SCR_2E_PromptWait, SCR_TRAP, SCR_30_Fight, /*30*/ SCR_31_Fight2, SCR_32_FightWin, SCR_33_Jump, SCR_34_Call, SCR_35_Ret, SCR_36_ChangeZone, SCR_37_DesciTextBox, SCR_38_PlayAnim, SCR_39_AnimRoomDoorOpen, SCR_3A_AnimRoomDoorClose, SCR_3B_MathExpr, SCR_3C_CondExpr, SCR_3D_ActionsMenu, SCR_3E_TheWallAdvance, SCR_TRAP, SCR_40_PopAllTextBoxes, /*40*/ SCR_41_LiftHand, SCR_42_LoadZone, SCR_43_RefreshZone, SCR_44_BackBufferToScreen, SCR_45_DeProfundisRoomEntry, SCR_46_DeProfundisLowerHook, SCR_47_DeProfundisRiseMonster, SCR_48_DeProfundisLowerMonster, SCR_49_DeProfundisRiseHook, SCR_TRAP, SCR_TRAP, SCR_4C_DrawZoneObjs, SCR_TRAP, SCR_4E_BounceCurrentItemToRoom, SCR_4F_BounceCurrentItemToInventory, SCR_50_BounceItemToInventory, /*50*/ SCR_51_ItemTrade, SCR_52_RefreshSpritesData, SCR_53_FindInvItem, SCR_TRAP, SCR_TRAP, SCR_TRAP, SCR_TRAP, SCR_TRAP, SCR_59_BlitSpritesToBackBuffer, SCR_5A_SelectPalette, SCR_TRAP, SCR_TRAP, SCR_TRAP, SCR_TRAP, SCR_5F_DrawRoomObjectBack, SCR_TRAP, /*60*/ SCR_61_DrawPersonBubbleDialog, SCR_TRAP, SCR_TRAP, SCR_64_DrawBoxAroundSpot, SCR_65_DeProfundisMovePlatform, SCR_66_DeProfundisRideToExit, SCR_67_Unused, SCR_68_Unused, SCR_69_PlaySound, SCR_6A_Unused, }; #define MAX_SCR_HANDLERS (sizeof(script_handlers) / sizeof(script_handlers[0])) #ifdef DEBUG_SCRIPT int runscr_reentr = 0; int runcmd_reentr = 0; #endif unsigned int RunScript(unsigned char *code) { unsigned int status = ScriptContinue; #ifdef DEBUG_SCRIPT runscr_reentr += 1; #endif script_ptr = code; while (script_ptr != script_end_ptr) { unsigned char opcode = *script_ptr; #ifdef DEBUG_SCRIPT { FILE *f = fopen(DEBUG_SCRIPT_LOG, "at"); if (f) { unsigned int offs = (script_ptr - templ_data) & 0xFFFF; fprintf(f, "%04X: %02X\n", offs, opcode); fclose(f); } } #endif #ifdef DEBUG_QUEST if (script_ptr - templ_data == 0x4F) { /*manipulate rand_value to get a quest item we need*/ script_byte_vars.rand_value = DEBUG_QUEST; } #endif if (opcode == 0 || opcode >= 107) break; status = script_handlers[opcode](); if (status != ScriptContinue) break; } #ifdef DEBUG_SCRIPT runscr_reentr -= 1; #endif return status; } unsigned char *GetScriptSubroutine(unsigned int index) { return SeekToEntry(templ_data, index, &script_end_ptr); } unsigned int RunCommand(void) { unsigned int res; unsigned short cmd; again: ; res = 0; if (the_command == 0) return 0; #ifdef DEBUG_SCRIPT { FILE *f = fopen(DEBUG_SCRIPT_LOG, "at"); if (f) { fprintf(f, "\nRunCommand 0x%04X rc: %d rs: %d\n", the_command, runcmd_reentr, runscr_reentr); fclose(f); } } runcmd_reentr += 1; #endif cmd = the_command & 0x3FF; switch (the_command & 0xF000) { case 0: /*TODO what kind of call is this?*/ res = RunScript(templ_data + the_command); break; case 0x9000: DrawMessage(SeekToString(desci_data, cmd), CGA_SCREENBUFFER); break; case 0xA000: case 0xB000: printf("Command: $%X 0x%X\n", the_command, cmd); res = command_handlers[cmd](); break; case 0xF000: /*restore sp from keep_sp*/ TODO("SCR_RESTORE\n"); default: res = RunScript(GetScriptSubroutine(cmd - 1)); } #ifdef DEBUG_SCRIPT runcmd_reentr -= 1; #endif #ifdef DEBUG_SCRIPT { FILE *f = fopen(DEBUG_SCRIPT_LOG, "at"); if (f) { fprintf(f, "\n"); fclose(f); } } #endif /*TODO: this is pretty hacky, original code manipulates the stack to discard old script invocation*/ if (res == ScriptRerun) goto again; return res; } unsigned int RunCommandKeepSp(void) { /*keep_sp = sp;*/ return RunCommand(); } } // End of namespace Chamber