534 lines
13 KiB
C
534 lines
13 KiB
C
// Copyright © 2016-2017 Graham Sanderson, all rights reserved.
|
|
#include "lith_common.h"
|
|
#include "lith_world.h"
|
|
#include "lith_player.h"
|
|
#include "lith_hudid.h"
|
|
#include "lith_dialogue.h"
|
|
|
|
#define Next_I (*++codeptr)
|
|
#define Next_S ((__str)Next_I)
|
|
|
|
#define DoCurCode goto *cases[*codeptr]
|
|
#define DoNextCode goto *cases[Next_I]
|
|
#define Done goto done
|
|
#define Op(name) opcase_##name
|
|
|
|
// Types ---------------------------------------------------------------------|
|
|
|
|
enum
|
|
{
|
|
ACT_NONE,
|
|
ACT_ACKNOWLEDGE,
|
|
ACT_SELOPTION,
|
|
ACT_EXIT,
|
|
};
|
|
|
|
enum
|
|
{
|
|
TACT_NONE,
|
|
TACT_LOGON,
|
|
TACT_LOGOFF,
|
|
TACT_INFO,
|
|
TACT_PICT,
|
|
};
|
|
|
|
typedef struct dlgoption_s
|
|
{
|
|
__str name;
|
|
int *ptr;
|
|
} dlgoption_t;
|
|
|
|
typedef struct dlgcurstate_s
|
|
{
|
|
__str trmPict;
|
|
int trmActi;
|
|
int trmTime;
|
|
} dlgcurstate_t;
|
|
|
|
typedef struct dlgvmstate_s
|
|
{
|
|
__str text;
|
|
|
|
int stk[16];
|
|
int *sptr;
|
|
|
|
__str sreg[4];
|
|
int rega;
|
|
int regb;
|
|
int regc;
|
|
int regd;
|
|
|
|
int action;
|
|
|
|
dlgoption_t option[8];
|
|
int optNum;
|
|
int optSel;
|
|
int concat;
|
|
|
|
anonymous dlgcurstate_t cur;
|
|
dlgcurstate_t next;
|
|
} dlgvmstate_t;
|
|
|
|
// Extern Objects ------------------------------------------------------------|
|
|
|
|
struct dlgdef *lmvar dlgdefs;
|
|
|
|
// Static Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lith_TerminalGUI
|
|
//
|
|
script static void Lith_TerminalGUI(gui_state_t *g, struct player *p, dlgvmstate_t *vmstate)
|
|
{
|
|
enum {
|
|
// background
|
|
sizex = 480, sizey = 360,
|
|
right = sizex,
|
|
top = sizey*.08,
|
|
bottom = sizey*.75,
|
|
|
|
midx = right/2, midy = bottom/2,
|
|
|
|
// text
|
|
tsizex = 640, tsizey = 400,
|
|
ttop = tsizey*.08,
|
|
tleft = tsizex/2-32
|
|
};
|
|
|
|
__str remote = vmstate->sreg[DSTR_REMOTE] ?
|
|
vmstate->sreg[DSTR_REMOTE] : "<unknown>@raddr.4E19";
|
|
|
|
Lith_GUI_Begin(g, hid_end_dialogue, sizex, sizey);
|
|
Lith_GUI_UpdateState(g, p);
|
|
|
|
// Background
|
|
DrawSpritePlain(":Terminal:Back", g->hid--, midx, 0.1, TS);
|
|
DrawSpritePlain(":Terminal:Border", g->hid--, midx, 0.1, TS);
|
|
|
|
// Top-left text
|
|
HudMessageF("LTRMFONT", "SGXLine r4205");
|
|
HudMessageParams(0, g->hid--, CR_RED, 0.1, 0.1, TS);
|
|
|
|
// Top-right text
|
|
switch(vmstate->trmActi)
|
|
{
|
|
case TACT_LOGON: HudMessageF("LTRMFONT", "Opening Connection to %S", remote); break;
|
|
case TACT_LOGOFF: HudMessageF("LTRMFONT", "Disconnecting..."); break;
|
|
default: HudMessageF("LTRMFONT", "Remote: %S", remote); break;
|
|
}
|
|
HudMessageParams(0, g->hid--, CR_RED, right+.2, 0.1, TS);
|
|
|
|
// Bottom-left text
|
|
HudMessageF("LTRMFONT", "<55.883.115.7>");
|
|
HudMessageParams(0, g->hid--, CR_RED, 0.1, bottom+.2, TS);
|
|
|
|
// Bottom-right text
|
|
switch(vmstate->trmActi)
|
|
{
|
|
case TACT_LOGON:
|
|
case TACT_LOGOFF: HudMessageF("LTRMFONT", "%S", world.canondate); break;
|
|
default: HudMessageF("LTRMFONT", "Use To Acknowledge"); break;
|
|
}
|
|
HudMessageParams(0, g->hid--, CR_RED, right+.2, bottom+.2, TS);
|
|
|
|
// Contents
|
|
__str pict;
|
|
|
|
if(vmstate->trmPict)
|
|
pict = StrParam(":Terminal:%S", vmstate->trmPict);
|
|
|
|
switch(vmstate->trmActi)
|
|
{
|
|
case TACT_LOGON:
|
|
case TACT_LOGOFF:
|
|
__with(int y = midy;)
|
|
{
|
|
if(vmstate->text != "")
|
|
{
|
|
HudMessageF("LTRMFONT", "%S", vmstate->text);
|
|
HudMessagePlain(g->hid--, midx, midy + 35, TS);
|
|
y -= 10;
|
|
}
|
|
|
|
DrawSpritePlain(StrParam(":Terminal:%S", vmstate->trmPict), g->hid--, midx, y, TS);
|
|
}
|
|
break;
|
|
|
|
case TACT_PICT:
|
|
DrawSpritePlain(StrParam(":Terminal:%S", vmstate->trmPict), g->hid--, midx/2, midy, TS);
|
|
ACS_SetHudSize(tsizex, tsizey, false);
|
|
ACS_SetHudClipRect(tleft, ttop, 300, 300, 300);
|
|
HudMessageF("LTRMFONT", "%S", vmstate->text);
|
|
HudMessagePlain(g->hid--, tleft+.1, ttop+.1, TS);
|
|
ACS_SetHudSize(g->w, g->h, false);
|
|
ACS_SetHudClipRect(0, 0, 0, 0);
|
|
break;
|
|
|
|
case TACT_INFO:
|
|
HudMessageF("LTRMFONT", "%S", vmstate->text);
|
|
HudMessagePlain(g->hid--, midx, midy, TS);
|
|
break;
|
|
}
|
|
|
|
Lith_GUI_End(g, gui_curs_outlineinv);
|
|
|
|
if(p->buttons & BT_USE && !(p->old.buttons & BT_USE) && p->old.indialogue)
|
|
{
|
|
ACS_LocalAmbientSound("player/trmswitch", 127);
|
|
vmstate->action = ACT_ACKNOWLEDGE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lith_DialogueGUI
|
|
//
|
|
script static void Lith_DialogueGUI(gui_state_t *g, struct player *p, dlgvmstate_t *vmstate)
|
|
{
|
|
enum {left = 37, top = 75};
|
|
__str icon = StrParam(":Dialogue:Icon%S", vmstate->sreg[DSTR_ICON]);
|
|
__str name = vmstate->sreg[DSTR_NAME];
|
|
__str remo = vmstate->sreg[DSTR_REMOTE];
|
|
|
|
Lith_GUI_Begin(g, hid_end_dialogue, 320, 240);
|
|
Lith_GUI_UpdateState(g, p);
|
|
|
|
DrawSpriteAlpha(":Dialogue:Back", g->hid--, 0.1, 0.1, TS, 0.7);
|
|
DrawSpriteAlpha(icon, g->hid--, 0.1, 0.1, TS, 0.7);
|
|
|
|
HudMessageF("LHUDFONT", "%S", name);
|
|
HudMessagePlain(g->hid--, 30.1, 35.1, TS);
|
|
|
|
HudMessageF("CBIFONT", "\Cd> Remote: %S\n\Cd> Date: %S\n\n%S",
|
|
remo, world.canontime, vmstate->text);
|
|
HudMessageParams(0, g->hid--, CR_WHITE, 37.1, 75.1, TS);
|
|
|
|
if(vmstate->optNum)
|
|
{
|
|
int y = 220 - (14 * vmstate->optNum);
|
|
for(int i = 0; i < vmstate->optNum; i++, y += 14)
|
|
{
|
|
if(Lith_GUI_Button_Id(g, i, vmstate->option[i].name, 45, y, Pre(btndlgsel)))
|
|
{
|
|
vmstate->action = ACT_SELOPTION;
|
|
vmstate->optSel = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
Lith_GUI_End(g, gui_curs_outlineinv);
|
|
}
|
|
|
|
//
|
|
// AddText
|
|
//
|
|
static __str AddText(dlgvmstate_t *vmstate, __str s, bool local)
|
|
{
|
|
if(!vmstate->concat) {
|
|
if(local) return StrParam("%S%LS\n", vmstate->text, s);
|
|
else return StrParam("%S%S\n", vmstate->text, s);
|
|
} else if(s != "") {
|
|
if(local) return StrParam("%S%LS ", vmstate->text, s);
|
|
else return StrParam("%S%S ", vmstate->text, s);
|
|
} else {
|
|
return StrParam("%S\n\n", vmstate->text);
|
|
}
|
|
}
|
|
|
|
// Extern Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lith_TeleportOutEffect
|
|
//
|
|
script acs void Lith_TeleportOutEffect(struct player *p)
|
|
{
|
|
if(!p) p = LocalPlayer;
|
|
|
|
ACS_AmbientSound("misc/teleout", 127);
|
|
|
|
ACS_SetHudSize(320, 200);
|
|
ACS_SetCameraToTexture(p->tid, "LITHCAM3", 90);
|
|
|
|
DrawSpritePlain(":Terminal:TeleportOut", hid_teleportback,
|
|
160.0, 100.0, 1);
|
|
|
|
for(int j = 1; j <= 25; j++)
|
|
{
|
|
fixed e = j / 25.f * 30;
|
|
ACS_SetHudSize(320 * e, 240);
|
|
DrawSpriteFade("LITHCAM3", hid_teleport, (int)(160 * e), 120, TS, 0.2);
|
|
ACS_Delay(1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lith_DialogueVM
|
|
//
|
|
// Main dialogue VM.
|
|
//
|
|
script void Lith_DialogueVM(struct player *p, int num)
|
|
{
|
|
if(p->dead || p->indialogue > 1)
|
|
return;
|
|
|
|
// Get the dialogue by number.
|
|
struct dlgdef *def;
|
|
|
|
for(def = dlgdefs; def && def->num != num; def = def->next);
|
|
if(!def) return;
|
|
|
|
p->indialogue++;
|
|
|
|
// GUI state
|
|
gui_state_t gst = {};
|
|
gst.gfxprefix = ":UI_Green:";
|
|
Lith_GUI_Init(&gst);
|
|
|
|
// VM state
|
|
dlgvmstate_t vmstate = {};
|
|
vmstate.text = "";
|
|
for(int i = 0; i < 4; i++)
|
|
vmstate.sreg[i] = "";
|
|
vmstate.sptr = &vmstate.stk[0];
|
|
|
|
// terminals are numbered negative
|
|
if(num < 0)
|
|
{
|
|
gst.cx = 320;
|
|
gst.cy = 200;
|
|
// TODO: determine mission status
|
|
}
|
|
else
|
|
{
|
|
gst.cx = 320 / 2;
|
|
gst.cy = 200 / 2;
|
|
}
|
|
|
|
for(int *codeptr = def->codeV + def->pages[0];;)
|
|
{
|
|
static __label *const cases[] = {
|
|
#define DCD(name) &&opcase_DCD_##name,
|
|
#include "lith_dialogue.h"
|
|
};
|
|
|
|
DoCurCode;
|
|
Op(DCD_NOP): DoNextCode;
|
|
Op(DCD_DIE): Done;
|
|
|
|
Op(DCD_PUSH_I): *(vmstate.sptr++) = Next_I; DoNextCode;
|
|
Op(DCD_PUSH_A): *(vmstate.sptr++) = vmstate.rega; DoNextCode;
|
|
Op(DCD_PUSH_B): *(vmstate.sptr++) = vmstate.regb; DoNextCode;
|
|
Op(DCD_PUSH_C): *(vmstate.sptr++) = vmstate.regc; DoNextCode;
|
|
Op(DCD_PUSH_D): *(vmstate.sptr++) = vmstate.regd; DoNextCode;
|
|
|
|
Op(DCD_POP): --vmstate.sptr ; DoNextCode;
|
|
Op(DCD_POP_A): vmstate.rega = *(--vmstate.sptr); DoNextCode;
|
|
Op(DCD_POP_B): vmstate.regb = *(--vmstate.sptr); DoNextCode;
|
|
Op(DCD_POP_C): vmstate.regc = *(--vmstate.sptr); DoNextCode;
|
|
Op(DCD_POP_D): vmstate.regd = *(--vmstate.sptr); DoNextCode;
|
|
|
|
#define Arith(op, r) \
|
|
vmstate.rega op##= r
|
|
#define ArithSet(sfx, r) \
|
|
Op(DCD_ADD_##sfx): Arith(+, r); DoNextCode; \
|
|
Op(DCD_SUB_##sfx): Arith(-, r); DoNextCode; \
|
|
Op(DCD_MUL_##sfx): Arith(*, r); DoNextCode; \
|
|
Op(DCD_DIV_##sfx): Arith(/, r); DoNextCode; \
|
|
Op(DCD_MOD_##sfx): Arith(%, r); DoNextCode; \
|
|
Op(DCD_IOR_##sfx): Arith(|, r); DoNextCode; \
|
|
Op(DCD_AND_##sfx): Arith(&, r); DoNextCode; \
|
|
Op(DCD_XOR_##sfx): Arith(^, r); DoNextCode; \
|
|
Op(DCD_LSH_##sfx): Arith(<<, r); DoNextCode; \
|
|
Op(DCD_RSH_##sfx): Arith(>>, r); DoNextCode
|
|
ArithSet(I, Next_I);
|
|
ArithSet(A, vmstate.rega);
|
|
ArithSet(B, vmstate.regb);
|
|
ArithSet(C, vmstate.regc);
|
|
ArithSet(D, vmstate.regd);
|
|
#undef Arith
|
|
#undef ArithSet
|
|
|
|
Op(DCD_JPAGE): codeptr = def->codeV + def->pages[Next_I]; DoCurCode;
|
|
Op(DCD_JMP): codeptr = def->codeV + Next_I; DoCurCode;
|
|
|
|
#define GenJump(check) \
|
|
__with(void *jmpto = def->codeV + Next_I;) \
|
|
if(check) {codeptr = jmpto; DoCurCode;} \
|
|
DoNextCode
|
|
Op(DCD_JNZ): GenJump(vmstate.sptr[-1] != 0);
|
|
Op(DCD_JNITEM): GenJump(!InvNum(Next_S));
|
|
Op(DCD_JNCLASS): GenJump(p->pclass != Next_I);
|
|
#undef GenJump
|
|
|
|
Op(DCD_SCRIPTI):
|
|
__with(int s = Next_I, a = Next_I, b = Next_I, c = Next_I, d = Next_I;)
|
|
ACS_ExecuteWithResult(s, a, b, c, d);
|
|
DoNextCode;
|
|
Op(DCD_SCRIPTS):
|
|
__with(__str s = Next_S; int a = Next_I, b = Next_I, c = Next_I, d = Next_I;)
|
|
ACS_NamedExecuteWithResult(s, a, b, c, d);
|
|
DoNextCode;
|
|
|
|
Op(DCD_TELEPORT_INTRALEVEL):
|
|
ACS_Delay(5);
|
|
ACS_Teleport(0, Next_I, false);
|
|
Done;
|
|
Op(DCD_TELEPORT_INTERLEVEL):
|
|
ACS_Delay(5);
|
|
Lith_TeleportOutEffect(p);
|
|
ACS_Delay(34);
|
|
ACS_Teleport_NewMap(Next_I, 0, 0);
|
|
Done;
|
|
|
|
Op(DCD_TRACE_S): Log("%S", Next_S ); DoNextCode;
|
|
Op(DCD_TRACE_A): Log("%.8X", vmstate.rega); DoNextCode;
|
|
Op(DCD_TRACE_B): Log("%.8X", vmstate.regb); DoNextCode;
|
|
Op(DCD_TRACE_C): Log("%.8X", vmstate.regc); DoNextCode;
|
|
Op(DCD_TRACE_D): Log("%.8X", vmstate.regd); DoNextCode;
|
|
|
|
Op(DCD_SETSTRING):
|
|
__with(int num = Next_I; __str str = Next_S;)
|
|
vmstate.sreg[num] = str;
|
|
DoNextCode;
|
|
|
|
Op(DCD_SETTEXT):
|
|
vmstate.text = Next_S; DoNextCode;
|
|
Op(DCD_SETTEXTLOCAL):
|
|
vmstate.text = StrParam("%LS", Next_S); DoNextCode;
|
|
Op(DCD_ADDTEXT):
|
|
vmstate.text = AddText(&vmstate, Next_S, false); DoNextCode;
|
|
Op(DCD_ADDTEXTLOCAL):
|
|
vmstate.text = AddText(&vmstate, Next_S, true); DoNextCode;
|
|
|
|
Op(DCD_CONCAT):
|
|
vmstate.concat++;
|
|
DoNextCode;
|
|
|
|
Op(DCD_CONCATEND):
|
|
vmstate.text = StrParam("%S\n", vmstate.text);
|
|
vmstate.concat--;
|
|
DoNextCode;
|
|
|
|
Op(DCD_PUTOPT):
|
|
__with(void *jmpto = def->codeV + Next_I;)
|
|
{
|
|
dlgoption_t *option = vmstate.option + vmstate.optNum++;
|
|
|
|
option->name = Next_S;
|
|
option->ptr = ++codeptr;
|
|
|
|
codeptr = jmpto;
|
|
}
|
|
DoCurCode;
|
|
|
|
Op(DCD_DLGWAIT):
|
|
ACS_LocalAmbientSound("player/cbi/dlgopen", 127);
|
|
|
|
p->frozen++;
|
|
p->setVel(0, 0, 0);
|
|
|
|
if(vmstate.text != "")
|
|
HudMessageLog("%S", vmstate.text);
|
|
|
|
do {
|
|
Lith_DialogueGUI(&gst, p, &vmstate);
|
|
ACS_Delay(1);
|
|
}
|
|
while(vmstate.action == ACT_NONE);
|
|
|
|
p->frozen--;
|
|
goto guiact;
|
|
|
|
Op(DCD_LOGON): vmstate.next.trmActi = TACT_LOGON; goto login;
|
|
Op(DCD_LOGOFF): vmstate.next.trmActi = TACT_LOGOFF; goto login;
|
|
Op(DCD_INFO): vmstate.next.trmActi = TACT_INFO; goto terminal;
|
|
Op(DCD_PICT): vmstate.next.trmActi = TACT_PICT; goto pict;
|
|
Op(DCD_TRMWAIT): goto terminal;
|
|
|
|
login:
|
|
vmstate.next.trmTime = 42;
|
|
pict:
|
|
vmstate.next.trmPict = Next_S;
|
|
terminal:
|
|
if(vmstate.trmActi != TACT_NONE)
|
|
{
|
|
if(vmstate.trmActi == TACT_LOGON || vmstate.trmActi == TACT_LOGOFF)
|
|
ACS_LocalAmbientSound("player/trmopen", 127);
|
|
|
|
bool timer = vmstate.trmTime != 0;
|
|
p->frozen++;
|
|
p->setVel(0, 0, 0);
|
|
|
|
if(vmstate.text != "")
|
|
HudMessageLog("%S", vmstate.text);
|
|
|
|
do {
|
|
Lith_TerminalGUI(&gst, p, &vmstate);
|
|
ACS_Delay(1);
|
|
}
|
|
while(vmstate.action == ACT_NONE &&
|
|
(!timer || --vmstate.trmTime >= 0));
|
|
|
|
p->frozen--;
|
|
}
|
|
|
|
vmstate.cur = vmstate.next;
|
|
vmstate.next.trmActi = TACT_NONE;
|
|
vmstate.next.trmTime = 0;
|
|
guiact:
|
|
__with(int action = vmstate.action;)
|
|
{
|
|
vmstate.action = ACT_NONE;
|
|
vmstate.text = "";
|
|
|
|
switch(action)
|
|
{
|
|
case ACT_ACKNOWLEDGE: break;
|
|
case ACT_SELOPTION:
|
|
codeptr = vmstate.option[vmstate.optSel].ptr;
|
|
vmstate.optSel = 0;
|
|
vmstate.optNum = 0;
|
|
DoCurCode;
|
|
case ACT_EXIT: Done;
|
|
}
|
|
}
|
|
DoNextCode;
|
|
}
|
|
|
|
done:
|
|
p->indialogue -= 2;
|
|
}
|
|
|
|
//
|
|
// Lith_RunDialogue
|
|
//
|
|
script acs void Lith_RunDialogue(int num)
|
|
{
|
|
withplayer(LocalPlayer) if(!p->indialogue)
|
|
{
|
|
p->dlgnum = num;
|
|
p->indialogue++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lith_RunTerminal
|
|
//
|
|
// Runs a numbered terminal.
|
|
//
|
|
script acs void Lith_RunTerminal(int num)
|
|
{
|
|
Lith_RunDialogue(-num);
|
|
}
|
|
|
|
//
|
|
// Lith_RunDialogueInt
|
|
//
|
|
scriptn address(24244) acs void Lith_RunDialogueInt(int num)
|
|
{
|
|
Lith_RunDialogue(num);
|
|
}
|
|
|
|
// EOF
|
|
|