mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-10 14:42:13 +00:00
Fix emulated support of hexen2's CState syntax.
This commit is contained in:
parent
1ce399e969
commit
73bb9969a1
4 changed files with 165 additions and 44 deletions
|
@ -558,6 +558,8 @@ enum qcop_e {
|
|||
OP_LSHIFT_DI,
|
||||
OP_RSHIFT_DI,
|
||||
|
||||
OP_WSTATE, //for the 'w' part of CWSTATE. will probably never be used, but hey, hexen2...
|
||||
|
||||
//special/fake opcodes used by the decompiler.
|
||||
OPD_GOTO_FORSTART,
|
||||
OPD_GOTO_WHILE1,
|
||||
|
|
|
@ -890,6 +890,8 @@ QCC_opcode_t pr_opcodes[] =
|
|||
{7, "<<", "LSHIFT_DI", PC_SHIFT, ASSOC_LEFT, &type_double, &type_integer, &type_double, OPF_STD},
|
||||
{7, ">>", "RSHIFT_DI", PC_SHIFT, ASSOC_LEFT, &type_double, &type_integer, &type_double, OPF_STD},
|
||||
|
||||
{7, "<WSTATE>", "WSTATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void},
|
||||
|
||||
{0, NULL, "OPD_GOTO_FORSTART"},
|
||||
{0, NULL, "OPD_GOTO_WHILE1"},
|
||||
|
||||
|
@ -968,6 +970,7 @@ static int OpAssignsCount(unsigned int op)
|
|||
case OP_CALL8H:
|
||||
return 0; //also, eep.
|
||||
case OP_STATE:
|
||||
case OP_WSTATE:
|
||||
case OP_CSTATE:
|
||||
case OP_CWSTATE:
|
||||
case OP_THINKTIME:
|
||||
|
@ -2253,7 +2256,7 @@ void QCC_FreeTemp(QCC_sref_t t)
|
|||
if (t.sym && t.sym->symbolheader)
|
||||
{
|
||||
if (--t.sym->symbolheader->refcount < 0)
|
||||
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: over-freed refcount to %s", t.sym->name);
|
||||
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: over-freed refcount to %s", QCC_VarAtOffset(t));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2277,7 +2280,7 @@ static void QCC_UnFreeTemp(QCC_sref_t t)
|
|||
if (t.sym && t.sym->symbolheader)
|
||||
{
|
||||
if (!t.sym->symbolheader->refcount++)
|
||||
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: %s+%i@%i was already fully freed.", t.sym->name, t.ofs, t.sym->ofs);
|
||||
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: %s+%i@%i was already fully freed.", QCC_VarAtOffset(t), t.ofs, t.sym->ofs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3625,21 +3628,56 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
|
|||
QCC_sref_t fldthink = QCC_PR_GetSRef(QCC_PR_FieldType(type_function), "think", NULL, true, 0, false);
|
||||
QCC_sref_t fldnextthink = QCC_PR_GetSRef(type_floatfield, "nextthink", NULL, true, 0, false);
|
||||
|
||||
QCC_UnFreeTemp(self);
|
||||
QCC_UnFreeTemp(self);
|
||||
|
||||
//self.frame = var_a;
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldframe, fldframe.cast->aux_type,
|
||||
true), var_a, false, false);
|
||||
false), var_a, false, false);
|
||||
|
||||
//self.think = var_b;
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldthink, fldthink.cast->aux_type,
|
||||
true), var_b, false, false);
|
||||
false), var_b, false, false);
|
||||
|
||||
//self.frame = time + interval;
|
||||
time = QCC_PR_Statement(&pr_opcodes[OP_ADD_F], time, QCC_MakeFloatConst(1/qcc_framerate), NULL);
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldnextthink, fldnextthink.cast->aux_type,
|
||||
true), time, false, false);
|
||||
false), time, false, false);
|
||||
return nullsref;
|
||||
}
|
||||
break;
|
||||
case OP_WSTATE:
|
||||
{ //there is no normal opcode.
|
||||
QCC_ref_t tempref;
|
||||
QCC_sref_t self = QCC_PR_GetSRef(type_entity, "self", NULL, true, 0, false);
|
||||
QCC_sref_t time = QCC_PR_GetSRef(type_float, "time", NULL, true, 0, false);
|
||||
QCC_sref_t fldframe = QCC_PR_GetSRef(type_floatfield, "weaponframe", NULL, true, 0, false);
|
||||
QCC_sref_t fldthink = QCC_PR_GetSRef(QCC_PR_FieldType(type_function), "think", NULL, true, 0, false);
|
||||
QCC_sref_t fldnextthink = QCC_PR_GetSRef(type_floatfield, "nextthink", NULL, true, 0, false);
|
||||
|
||||
float framerate = (qcc_framerate>0)?qcc_framerate:(qcc_targetformat_ishexen2()?20:10);
|
||||
|
||||
QCC_UnFreeTemp(self);
|
||||
QCC_UnFreeTemp(self);
|
||||
|
||||
//self.frame = var_a;
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldframe, fldframe.cast->aux_type,
|
||||
false), var_a, false, false);
|
||||
|
||||
//self.think = var_b;
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldthink, fldthink.cast->aux_type,
|
||||
false), var_b, false, false);
|
||||
|
||||
//self.frame = time + interval;
|
||||
time = QCC_PR_Statement(&pr_opcodes[OP_ADD_F], time, QCC_MakeFloatConst(1/framerate), NULL);
|
||||
QCC_StoreSRefToRef(QCC_PR_BuildRef(&tempref, REF_FIELD, self,
|
||||
fldnextthink, fldnextthink.cast->aux_type,
|
||||
false), time, false, false);
|
||||
return nullsref;
|
||||
}
|
||||
break;
|
||||
|
@ -14427,77 +14465,145 @@ void QCC_PR_ParseState (void)
|
|||
{
|
||||
QCC_sref_t s1, def;
|
||||
|
||||
pbool isinc;
|
||||
|
||||
//FIXME: this is ambiguous with pre-inc and post-inc logic.
|
||||
if (QCC_PR_CheckToken("++") || QCC_PR_CheckToken("--"))
|
||||
if ((isinc=QCC_PR_CheckToken("++")) || QCC_PR_CheckToken("--"))
|
||||
{
|
||||
s1 = QCC_PR_ParseImmediate ();
|
||||
const QCC_eval_t *first, *last;
|
||||
int dir = 0;
|
||||
int op = OP_CSTATE;
|
||||
if (QCC_PR_CheckToken("("))
|
||||
{
|
||||
op = OP_CWSTATE;
|
||||
if (!QCC_PR_CheckToken("w"))
|
||||
QCC_PR_Expect("W");
|
||||
QCC_PR_Expect(")");
|
||||
}
|
||||
|
||||
// s1 = QCC_PR_ParseImmediate ();
|
||||
|
||||
s1 = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA);
|
||||
s1 = QCC_SupplyConversion(s1, ev_float, true);
|
||||
|
||||
QCC_PR_Expect("..");
|
||||
def = QCC_PR_ParseImmediate ();
|
||||
// def = QCC_PR_ParseImmediate ();
|
||||
def = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA);
|
||||
def = QCC_SupplyConversion(def, ev_float, true);
|
||||
QCC_PR_Expect ("]");
|
||||
|
||||
if (s1.cast->type != ev_float || def.cast->type != ev_float)
|
||||
QCC_PR_ParseError(ERR_STATETYPEMISMATCH, "state type mismatch");
|
||||
|
||||
|
||||
if (QCC_OPCodeValid(&pr_opcodes[OP_CSTATE]))
|
||||
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_CSTATE], s1, def, NULL));
|
||||
first = QCC_SRef_EvalConst(s1);
|
||||
last = QCC_SRef_EvalConst(def);
|
||||
if (first&&last)
|
||||
{ //whether its a ++ or -- doesn't really matter, but hcc generates an error so we should at least generate a warning.
|
||||
dir = (last->_float >= first->_float)?1:-1;
|
||||
if (isinc)
|
||||
{
|
||||
if (first->_float > last->_float)
|
||||
QCC_PR_ParseWarning(ERR_STATETYPEMISMATCH, "Forwards State Cycle with backwards range");
|
||||
}
|
||||
else
|
||||
{
|
||||
QCC_statement_t *patch1, *entercyc, *fwd, *back;
|
||||
if (first->_float < last->_float)
|
||||
QCC_PR_ParseWarning(ERR_STATETYPEMISMATCH, "Forwards State Cycle with backwards range");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (QCC_OPCodeValid(&pr_opcodes[op]))
|
||||
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[op], s1, def, NULL));
|
||||
else
|
||||
{
|
||||
QCC_statement_t *patch1, *entercycf, *entercycb, *fwd, *back;
|
||||
QCC_sref_t t1, t2;
|
||||
QCC_sref_t framef, frame;
|
||||
QCC_sref_t self;
|
||||
QCC_sref_t cycle_wrapped;
|
||||
|
||||
self = QCC_PR_GetSRef(type_entity, "self", NULL, false, 0, false);
|
||||
framef = QCC_PR_GetSRef(NULL, "frame", NULL, false, 0, false);
|
||||
framef = QCC_PR_GetSRef(NULL, (op==OP_CWSTATE)?"weaponframe":"frame", NULL, false, 0, false);
|
||||
cycle_wrapped = QCC_PR_GetSRef(type_float, "cycle_wrapped", NULL, false, 0, false);
|
||||
|
||||
frame = QCC_PR_Statement(&pr_opcodes[OP_LOAD_F], self, framef, NULL);
|
||||
frame = QCC_PR_StatementFlags(&pr_opcodes[OP_LOAD_F], self, framef, NULL, 0);
|
||||
if (cycle_wrapped.cast)
|
||||
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(0), cycle_wrapped, NULL));
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(0), cycle_wrapped, NULL, STFL_PRESERVEB));
|
||||
|
||||
if (dir)
|
||||
fwd = NULL; //can skip the checks
|
||||
else
|
||||
{
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_GE_F], def, s1, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
fwd = QCC_Generate_OP_IFNOT(t1, false);
|
||||
}
|
||||
if (dir >= 0)
|
||||
{ //this block is the 'it's in a forwards direction'
|
||||
//make sure the frame is within the bounds given.
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], frame, s1, NULL, STFL_PRESERVEA);
|
||||
t2 = QCC_PR_StatementFlags(&pr_opcodes[OP_GT_F], frame, def, NULL, STFL_PRESERVEA);
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], frame, s1, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
t2 = QCC_PR_StatementFlags(&pr_opcodes[OP_GT_F], frame, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
t1 = QCC_PR_Statement(&pr_opcodes[OP_OR_F], t1, t2, NULL);
|
||||
patch1 = QCC_Generate_OP_IFNOT(t1, false);
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEB));
|
||||
entercyc = QCC_Generate_OP_GOTO();
|
||||
{
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEA|STFL_PRESERVEB));
|
||||
entercycf = QCC_Generate_OP_GOTO();
|
||||
}
|
||||
patch1->b.ofs = &statements[numstatements] - patch1;
|
||||
|
||||
t1 = QCC_PR_Statement(&pr_opcodes[OP_GE_F], def, s1, NULL);
|
||||
fwd = QCC_Generate_OP_IFNOT(t1, false); //this block is the 'it's in a forwards direction'
|
||||
{
|
||||
QCC_PR_SimpleStatement(&pr_opcodes[OP_ADD_F], frame, QCC_MakeFloatConst(1), frame, false);
|
||||
t1 = QCC_PR_Statement(&pr_opcodes[OP_GT_F], frame, def, NULL);
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_GT_F], frame, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
patch1 = QCC_Generate_OP_IFNOT(t1, false);
|
||||
{
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEB));
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEA|STFL_PRESERVEB));
|
||||
if (cycle_wrapped.cast)
|
||||
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1), cycle_wrapped, NULL));
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1), cycle_wrapped, NULL, STFL_PRESERVEB));
|
||||
}
|
||||
patch1->b.ofs = &statements[numstatements] - patch1;
|
||||
}
|
||||
else entercycf = NULL;
|
||||
if (fwd)
|
||||
{
|
||||
back = QCC_Generate_OP_GOTO();
|
||||
fwd->b.ofs = &statements[numstatements] - fwd;
|
||||
{
|
||||
//reverse animation.
|
||||
QCC_PR_SimpleStatement(&pr_opcodes[OP_SUB_F], frame, QCC_MakeFloatConst(1), frame, false);
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], frame, s1, NULL, STFL_PRESERVEA);
|
||||
}
|
||||
else
|
||||
back = NULL;
|
||||
if (dir <= 0)
|
||||
{ //reverse animation.
|
||||
|
||||
//make sure the frame is within the bounds given.
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_GT_F], frame, s1, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
t2 = QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], frame, def, NULL, STFL_PRESERVEA|STFL_PRESERVEB);
|
||||
t1 = QCC_PR_Statement(&pr_opcodes[OP_OR_F], t1, t2, NULL);
|
||||
patch1 = QCC_Generate_OP_IFNOT(t1, false);
|
||||
{
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], def, frame, NULL, STFL_PRESERVEB));
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEA|STFL_PRESERVEB));
|
||||
entercycb = QCC_Generate_OP_GOTO();
|
||||
}
|
||||
patch1->b.ofs = &statements[numstatements] - patch1;
|
||||
|
||||
QCC_PR_SimpleStatement(&pr_opcodes[OP_SUB_F], frame, QCC_MakeFloatConst(1), frame, false);
|
||||
t1 = QCC_PR_StatementFlags(&pr_opcodes[OP_LT_F], frame, def, NULL, STFL_PRESERVEA);
|
||||
patch1 = QCC_Generate_OP_IFNOT(t1, false);
|
||||
{
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], s1, frame, NULL, STFL_PRESERVEB));
|
||||
if (cycle_wrapped.cast)
|
||||
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1), cycle_wrapped, NULL));
|
||||
QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(1), cycle_wrapped, NULL, 0));
|
||||
}
|
||||
patch1->b.ofs = &statements[numstatements] - patch1;
|
||||
}
|
||||
back->b.ofs = &statements[numstatements] - back;
|
||||
else entercycb = NULL;
|
||||
|
||||
/*out of range*/entercyc->b.ofs = &statements[numstatements] - entercyc;
|
||||
if (back)
|
||||
back->a.ofs = &statements[numstatements] - back;
|
||||
|
||||
if (entercycf)
|
||||
/*out of range*/entercycf->a.ofs = &statements[numstatements] - entercycf;
|
||||
if (entercycb)
|
||||
/*out of range*/entercycb->a.ofs = &statements[numstatements] - entercycb;
|
||||
//self.frame = frame happens with the normal state opcode.
|
||||
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_STATE], frame, QCC_MakeSRef(pr_scope->def, 0, pr_scope->type), NULL));
|
||||
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[(op==OP_CWSTATE)?OP_WSTATE:OP_STATE], frame, QCC_MakeSRef(pr_scope->def, 0, pr_scope->type), NULL));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1139,6 +1139,8 @@ static pbool QCC_PR_Precompiler(void)
|
|||
else if (!QC_strcasecmp(qcc_token, "framerate"))
|
||||
{
|
||||
qcc_framerate = atof(msg);
|
||||
if (qcc_framerate < 0)
|
||||
qcc_framerate = 0;
|
||||
}
|
||||
else if (!QC_strcasecmp(qcc_token, "once"))
|
||||
{
|
||||
|
|
|
@ -4782,6 +4782,10 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
else
|
||||
QCC_PR_Warning(WARN_BADPARAMS, "cmdline", 0, "Unrecognised std parameter (%s)", myargv[i]);
|
||||
}
|
||||
else if (!strnicmp(myargv[i], "-state-fps=", 11))
|
||||
{
|
||||
qcc_framerate = atof(myargv[i]+11);
|
||||
}
|
||||
else if ( !strnicmp(myargv[i], "-F", 2) || WINDOWSARG(!strnicmp(myargv[i], "/F", 2)) )
|
||||
{
|
||||
pbool state;
|
||||
|
@ -4816,6 +4820,13 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
|||
flag_ifstring = state;
|
||||
else if (!stricmp(arg, "true-empty-strings"))
|
||||
flag_brokenifstring = state;
|
||||
else if (!stricmp(arg, "emulate-state"))
|
||||
{
|
||||
if (qcc_framerate>0 && state)
|
||||
;//already on, don't force if they already gave it an actual rate.
|
||||
else
|
||||
qcc_framerate = state?10:0;
|
||||
}
|
||||
else if (!stricmp(arg, "arithmetic-exceptions"))
|
||||
qccwarningaction[WARN_DIVISIONBY0] = state?WA_ERROR:WA_IGNORE;
|
||||
else if (!stricmp(arg, "lno"))
|
||||
|
|
Loading…
Reference in a new issue