//Returns the new program statement counter int PR_EnterFunction (dfunction_t *f) { int i, j, c, o; pr_stack[pr_depth].s = pr_xstatement; pr_stack[pr_depth].f = pr_xfunction; pr_depth++; if (pr_depth >= MAX_STACK_DEPTH) PR_RunError ("stack overflow"); // save off any locals that the new function steps on c = f->locals; if (localstack_used + c > LOCALSTACK_SIZE) PR_RunError ("PR_ExecuteProgram: locals stack overflow\n"); for (i = 0; i < c; i++) localstack[localstack_used+i] = ((int *) pr_globals)[f->parm_start + i]; localstack_used += c; // copy parameters o = f->parm_start; for (i = 0; i < f->numparms; i++) { for (j = 0; j < f->parm_size[i]; j++) { ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j]; o++; } } pr_xfunction = f; return f->first_statement - 1; // offset the s++ }
void SV_ParseMultiEffect (sizebuf_t *sb) { int idx, count; byte effect; vec3_t orig, vel; MultiEffectIdCount = 0; effect = G_FLOAT(OFS_PARM0); switch (effect) { case CE_HWRAVENPOWER: // need to set aside 3 effect ids MSG_WriteByte (sb, svc_multieffect); MSG_WriteByte (sb, effect); VectorCopy(G_VECTOR(OFS_PARM1), orig); MSG_WriteCoord(sb, orig[0]); MSG_WriteCoord(sb, orig[1]); MSG_WriteCoord(sb, orig[2]); VectorCopy(G_VECTOR(OFS_PARM2), vel); MSG_WriteCoord(sb, vel[0]); MSG_WriteCoord(sb, vel[1]); MSG_WriteCoord(sb, vel[2]); for (count = 0 ; count < 3 ; count++) { for (idx = 0 ; idx < MAX_EFFECTS ; idx++) { if (!sv.Effects[idx].type || (sv.Effects[idx].expire_time && sv.Effects[idx].expire_time <= sv.time)) break; } if (idx >= MAX_EFFECTS) { PR_RunError ("MAX_EFFECTS reached"); return; } MSG_WriteByte(sb, idx); sv.Effects[idx].type = CE_HWRAVENPOWER; VectorCopy(orig, sv.Effects[idx].ef.Missile.origin); VectorCopy(vel, sv.Effects[idx].ef.Missile.velocity); sv.Effects[idx].expire_time = sv.time + 10; MultiEffectIds[count] = idx; } break; default: PR_RunError ("%s: bad type", __thisfunc__); } }
VISIBLE void PR_BoundsCheckSize (progs_t *pr, pointer_t addr, unsigned size) { if (addr < (pointer_t) (pr->pr_return - pr->pr_globals)) PR_RunError (pr, "null pointer access"); if (addr >= pr->globals_size || size > (unsigned) (pr->globals_size - addr)) PR_RunError (pr, "invalid memory access: %d (0 to %d-%d)", addr, pr->globals_size, size); if (pr_boundscheck->int_val >= 2 && PR_GetPointer (pr, addr + size) > (pr_type_t *) pr->zone) { void *mem = (void *) PR_GetPointer (pr, addr); Z_CheckPointer (pr->zone, mem, size * sizeof (pr_type_t)); } }
static int LeaveFunction(void) { int i, c; if(pr_depth <= 0) { Sys_Error("prog stack underflow"); } // Restore locals from the stack c = pr_xfunction->locals; localstack_used -= c; if(localstack_used < 0) { PR_RunError("PR_ExecuteProgram: locals stack underflow\n"); } for (i=0 ; i < c ; i++) { ((int *)pr_globals)[pr_xfunction->parm_start+i] = localstack[localstack_used+i]; } // up stack pr_depth--; pr_xfunction = pr_stack[pr_depth].f; return pr_stack[pr_depth].s; }
// 2000-05-02 NVS SVC by Maddes void PF_NVS_InitSVCMsg(void) { edict_t *ent; int entnum; client_t *client; client = NULL; ent = G_EDICT(OFS_PARM3); entnum = NUM_FOR_EDICT(ent); if (entnum == 0) // world means all clients { client = NULL; } else if (entnum < 1 || entnum > svs.maxclients) { PR_RunError ("PF_NVS_InitSVCMsg: entity not a client"); } else { client = &svs.clients[entnum-1]; } NVS_InitSVCMsg(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2), client); }
pbool PR_SwitchProgs(progfuncs_t *progfuncs, progsnum_t type) { if ((unsigned)type >= maxprogs) PR_RunError(progfuncs, "QCLIB: Bad prog type - %i", type); // Sys_Error("Bad prog type - %i", type); if (pr_progstate[(unsigned)type].progs == NULL) //we havn't loaded it yet, for some reason return false; current_progstate = &pr_progstate[(unsigned)type]; pr_typecurrent = type; return true; }
static void PR_LeaveFunction (progs_t *pr) { int c; bfunction_t *f = pr->pr_xfunction; PR_PopFrame (pr); // restore locals from the stack c = f->locals; pr->localstack_used -= c; if (pr->localstack_used < 0) PR_RunError (pr, "PR_LeaveFunction: locals stack underflow"); memcpy (&pr->pr_globals[f->parm_start], &pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c); }
VISIBLE int PR_CallFunction (progs_t *pr, func_t fnum) { bfunction_t *f; if (!fnum) PR_RunError (pr, "NULL function"); f = pr->function_table + fnum; if (f->first_statement < 0) { // negative statements are built in functions f->func (pr); return 0; } else { PR_EnterFunction (pr, f); return 1; } }
VISIBLE inline void PR_PushFrame (progs_t *pr) { prstack_t *frame; if (pr->pr_depth == MAX_STACK_DEPTH) PR_RunError (pr, "stack overflow"); frame = pr->pr_stack + pr->pr_depth++; frame->s = pr->pr_xstatement; frame->f = pr->pr_xfunction; frame->tstr = pr->pr_xtstr; pr->pr_xtstr = 0; pr->pr_xfunction = 0; }
void PR_MoveParms(progfuncs_t *progfuncs, progsnum_t newpr, progsnum_t oldpr) //from 2 to 1 { unsigned int a; progstate_t *np; progstate_t *op; if (newpr == oldpr) return; //don't bother coping variables to themselves... np = &pr_progstate[(int)newpr]; op = &pr_progstate[(int)oldpr]; if ((unsigned)newpr >= maxprogs || !np->globals) PR_RunError(progfuncs, "QCLIB: Bad prog type - %i", newpr); if ((unsigned)oldpr >= maxprogs || !op->globals) return; //copy parms. for (a = 0; a < MAX_PARMS;a++) { *(int *)&np->globals[OFS_PARM0+3*a ] = *(int *)&op->globals[OFS_PARM0+3*a ]; *(int *)&np->globals[OFS_PARM0+3*a+1] = *(int *)&op->globals[OFS_PARM0+3*a+1]; *(int *)&np->globals[OFS_PARM0+3*a+2] = *(int *)&op->globals[OFS_PARM0+3*a+2]; } np->globals[OFS_RETURN] = op->globals[OFS_RETURN]; np->globals[OFS_RETURN+1] = op->globals[OFS_RETURN+1]; np->globals[OFS_RETURN+2] = op->globals[OFS_RETURN+2]; //move the vars defined as shared. for (a = 0; a < numshares; a++)//fixme: make offset per progs { memmove(&((int *)np->globals)[shares[a].varofs], &((int *)op->globals)[shares[a].varofs], shares[a].size*4); /* ((int *)p1->globals)[shares[a].varofs] = ((int *)p2->globals)[shares[a].varofs]; if (shares[a].size > 1) { ((int *)p1->globals)[shares[a].varofs+1] = ((int *)p2->globals)[shares[a].varofs+1]; if (shares[a].size > 2) ((int *)p1->globals)[shares[a].varofs+2] = ((int *)p2->globals)[shares[a].varofs+2]; } */ } }
/* PR_LeaveFunction */ int PR_LeaveFunction (progs_t *pr) { int i, c; if (pr->pr_depth <= 0) SV_Error ("prog stack underflow"); // restore locals from the stack c = pr->pr_xfunction->locals; pr->localstack_used -= c; if (pr->localstack_used < 0) PR_RunError (pr, "PR_ExecuteProgram: locals stack underflow\n"); for (i = 0; i < c; i++) ((int *) pr->pr_globals)[pr->pr_xfunction->parm_start + i] = pr->localstack[pr->localstack_used + i]; // up stack pr->pr_depth--; pr->pr_xfunction = pr->pr_stack[pr->pr_depth].f; return pr->pr_stack[pr->pr_depth].s; }
void PR_ExecuteProgram (func_t fnum) { eval_t *a, *b, *c; int s, runaway, i, exitdepth; dstatement_t *st; dfunction_t *f, *newf; edict_t *ed; eval_t *ptr; //Tei: enhanced vm #if 0 //TODO: this able self.think = remove(); // ..test this. If work, enable. if (fnum<0) { //Call a builtin i = -fnum; if (i >= pr_numbuiltins) PR_RunError ("Bad builtin call number '%d'", i); pr_builtins[i] (); return; } #endif if (!fnum || fnum >= progs->numfunctions) { if (pr_global_struct->self) ED_Print (PROG_TO_EDICT(pr_global_struct->self)); Host_Error ("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; runaway = 1000000;//Tei: x10 deeper functions pr_trace = false; // make a stack frame exitdepth = pr_depth; s = PR_EnterFunction (f); while (1) { s++; // next statement st = &pr_statements[s]; a = (eval_t *) &pr_globals[st->a]; b = (eval_t *) &pr_globals[st->b]; c = (eval_t *) &pr_globals[st->c]; if (--runaway == 0) PR_RunError ("runaway loop error"); pr_xfunction->profile++; pr_xstatement = s; if (pr_trace) PR_PrintStatement (st); switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: VectorAdd(a->vector, b->vector, c->vector); break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: VectorSubtract(a->vector, b->vector, c->vector); break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0] * b->vector[0] + a->vector[1] * b->vector[1] + a->vector[2] * b->vector[2]; break; case OP_MUL_FV: VectorScale(b->vector, a->_float, c->vector); break; case OP_MUL_VF: VectorScale(a->vector, b->_float, c->vector); break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int) a->_float & (int) b->_float; break; case OP_BITOR: c->_float = (int) a->_float | (int) b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !*PR_GetString(a->string); break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = VectorCompare(a->vector, b->vector); break; case OP_EQ_S: c->_float = !strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = !VectorCompare(a->vector, b->vector); break; case OP_NE_S: c->_float = strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; //================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: VectorCopy(a->vector, b->vector); break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *) ((byte *) sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); VectorCopy(a->vector, ptr->vector); break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif if (ed == (edict_t *) sv.edicts && sv.state == ss_active) PR_RunError ("assignment to world entity"); c->_int = (byte *) ((int *) &ed->v + b->_int) - (byte *) sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *) ((int *) &ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *) ((int *) &ed->v + b->_int); VectorCopy(a->vector, c->vector); break; //================== case OP_IFNOT: if (!a->_int) s += st->b - 1; // offset the s++ break; case OP_IF: if (a->_int) s += st->b - 1; // offset the s++ break; case OP_GOTO: s += st->a - 1; // offset the s++ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr_argc = st->op - OP_CALL0; if (!a->function) PR_RunError ("NULL function"); newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // negative statements are built in functions i = -newf->first_statement; if (i < pr_numbuiltins && pr_builtins[i]) pr_builtins[i](); else PR_RunError ("No such builtin #%i", i); break; } s = PR_EnterFunction (newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[st->a]; pr_globals[OFS_RETURN + 1] = pr_globals[st->a + 1]; pr_globals[OFS_RETURN + 2] = pr_globals[st->a + 2]; s = PR_LeaveFunction (); if (pr_depth == exitdepth) return; // all done break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); ed->v.nextthink = pr_global_struct->time + 0.1; if (a->_float != ed->v.frame) ed->v.frame = a->_float; ed->v.think = b->function; break; default: PR_RunError ("Bad opcode %i", st->op); } } }
void PR_ExecuteProgram (progs_t *pr, func_t fnum) { dstatement_t *st; dfunction_t *f, *newf; edict_t *ed; int exitdepth; eval_t *ptr; int profile, startprofile; if (!fnum || fnum >= pr->progs->numfunctions) { if (pr->pr_global_struct->self) ED_Print (pr, PROG_TO_EDICT (pr, pr->pr_global_struct->self)); SV_Error ("PR_ExecuteProgram: NULL function"); } f = &pr->pr_functions[fnum]; pr->pr_trace = false; // make a stack frame exitdepth = pr->pr_depth; st = &pr->pr_statements[PR_EnterFunction (pr, f)]; startprofile = profile = 0; while (1) { st++; if (++profile > 1000000) // LordHavoc: increased runaway loop // limit 10x { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "runaway loop error"); } if (pr->pr_trace) PR_PrintStatement (pr, st); switch (st->op) { case OP_ADD_F: OPC->_float = OPA->_float + OPB->_float; break; case OP_ADD_V: OPC->vector[0] = OPA->vector[0] + OPB->vector[0]; OPC->vector[1] = OPA->vector[1] + OPB->vector[1]; OPC->vector[2] = OPA->vector[2] + OPB->vector[2]; break; case OP_SUB_F: OPC->_float = OPA->_float - OPB->_float; break; case OP_SUB_V: OPC->vector[0] = OPA->vector[0] - OPB->vector[0]; OPC->vector[1] = OPA->vector[1] - OPB->vector[1]; OPC->vector[2] = OPA->vector[2] - OPB->vector[2]; break; case OP_MUL_F: OPC->_float = OPA->_float * OPB->_float; break; case OP_MUL_V: OPC->_float = OPA->vector[0] * OPB->vector[0] + OPA->vector[1] * OPB->vector[1] + OPA->vector[2] * OPB->vector[2]; break; case OP_MUL_FV: OPC->vector[0] = OPA->_float * OPB->vector[0]; OPC->vector[1] = OPA->_float * OPB->vector[1]; OPC->vector[2] = OPA->_float * OPB->vector[2]; break; case OP_MUL_VF: OPC->vector[0] = OPB->_float * OPA->vector[0]; OPC->vector[1] = OPB->_float * OPA->vector[1]; OPC->vector[2] = OPB->_float * OPA->vector[2]; break; case OP_DIV_F: OPC->_float = OPA->_float / OPB->_float; break; case OP_BITAND: OPC->_float = (int) OPA->_float & (int) OPB->_float; break; case OP_BITOR: OPC->_float = (int) OPA->_float | (int) OPB->_float; break; case OP_GE: OPC->_float = OPA->_float >= OPB->_float; break; case OP_LE: OPC->_float = OPA->_float <= OPB->_float; break; case OP_GT: OPC->_float = OPA->_float > OPB->_float; break; case OP_LT: OPC->_float = OPA->_float < OPB->_float; break; case OP_AND: OPC->_float = OPA->_float && OPB->_float; break; case OP_OR: OPC->_float = OPA->_float || OPB->_float; break; case OP_NOT_F: OPC->_float = !OPA->_float; break; case OP_NOT_V: OPC->_float = VectorIsNull(OPA->vector); break; case OP_NOT_S: OPC->_float = !OPA->string || !*PR_GetString (pr, OPA->string); break; case OP_NOT_FNC: OPC->_float = !OPA->function; break; case OP_NOT_ENT: OPC->_float = (PROG_TO_EDICT (pr, OPA->edict) == *pr->edicts); break; case OP_EQ_F: OPC->_float = OPA->_float == OPB->_float; break; case OP_EQ_V: OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]); break; case OP_EQ_S: OPC->_float = !strcmp (PR_GetString (pr, OPA->string), PR_GetString (pr, OPB->string)); break; case OP_EQ_E: OPC->_float = OPA->_int == OPB->_int; break; case OP_EQ_FNC: OPC->_float = OPA->function == OPB->function; break; case OP_NE_F: OPC->_float = OPA->_float != OPB->_float; break; case OP_NE_V: OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]); break; case OP_NE_S: OPC->_float = strcmp (PR_GetString (pr, OPA->string), PR_GetString (pr, OPB->string)); break; case OP_NE_E: OPC->_float = OPA->_int != OPB->_int; break; case OP_NE_FNC: OPC->_float = OPA->function != OPB->function; break; // ================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers OPB->_int = OPA->_int; break; case OP_STORE_V: OPB->vector[0] = OPA->vector[0]; OPB->vector[1] = OPA->vector[1]; OPB->vector[2] = OPA->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int + 4 > pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an out of bounds edict\n"); return; } if (pr_boundscheck->int_val && (OPB->_int % pr->pr_edict_size < ((byte *) & (*pr->edicts)->v - (byte *) *pr->edicts))) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an engine edict field\n"); return; } ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int); ptr->_int = OPA->_int; break; case OP_STOREP_V: if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int + 12 > pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an out of bounds edict\n"); return; } ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int); ptr->vector[0] = OPA->vector[0]; ptr->vector[1] = OPA->vector[1]; ptr->vector[2] = OPA->vector[2]; break; case OP_ADDRESS: if (pr_boundscheck->int_val && (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to address an out of bounds edict\n"); return; } if (pr_boundscheck->int_val && (OPA->edict == 0 && pr->null_bad)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "assignment to world entity"); return; } if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to address an invalid field in an edict\n"); return; } ed = PROG_TO_EDICT (pr, OPA->edict); OPC->_int = (byte *) ((int *) &ed->v + OPB->_int) - (byte *) *pr->edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: if (pr_boundscheck->int_val && (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an out of bounds edict number\n"); return; } if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an invalid field in an edict\n"); return; } ed = PROG_TO_EDICT (pr, OPA->edict); OPC->_int = ((eval_t *) ((int *) &ed->v + OPB->_int))->_int; break; case OP_LOAD_V: if (pr_boundscheck->int_val && (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an out of bounds edict number\n"); return; } if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int + 2 >= pr->progs->entityfields)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an invalid field in an edict\n"); return; } ed = PROG_TO_EDICT (pr, OPA->edict); OPC->vector[0] = ((eval_t *) ((int *) &ed->v + OPB->_int))->vector[0]; OPC->vector[1] = ((eval_t *) ((int *) &ed->v + OPB->_int))->vector[1]; OPC->vector[2] = ((eval_t *) ((int *) &ed->v + OPB->_int))->vector[2]; break; // ================== case OP_IFNOT: if (!OPA->_int) st += st->b - 1; // offset the s++ break; case OP_IF: if (OPA->_int) st += st->b - 1; // offset the s++ break; case OP_GOTO: st += st->a - 1; // offset the s++ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; pr->pr_xstatement = st - pr->pr_statements; pr->pr_argc = st->op - OP_CALL0; if (!OPA->function) PR_RunError (pr, "NULL function"); newf = &pr->pr_functions[OPA->function]; if (newf->first_statement < 0) { // negative // statements are // built in functions int i = -newf->first_statement; if (i >= pr_numbuiltins) PR_RunError (pr, "Bad builtin call number"); pr_builtins[i] (pr); break; } st = &pr->pr_statements[PR_EnterFunction (pr, newf)]; break; case OP_DONE: case OP_RETURN: pr->pr_globals[OFS_RETURN] = pr->pr_globals[(unsigned short) st->a]; pr->pr_globals[OFS_RETURN + 1] = pr->pr_globals[(unsigned short) st->a + 1]; pr->pr_globals[OFS_RETURN + 2] = pr->pr_globals[(unsigned short) st->a + 2]; st = &pr->pr_statements[PR_LeaveFunction (pr)]; if (pr->pr_depth == exitdepth) return; // all done break; case OP_STATE: ed = PROG_TO_EDICT (pr, pr->pr_global_struct->self); ed->v.v.nextthink = pr->pr_global_struct->time + 0.1; ed->v.v.frame = OPA->_float; ed->v.v.think = OPB->function; break; // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* case OP_ADD_I: OPC->_int = OPA->_int + OPB->_int; break; case OP_ADD_IF: OPC->_int = OPA->_int + (int) OPB->_float; break; case OP_ADD_FI: OPC->_float = OPA->_float + (float) OPB->_int; break; case OP_SUB_I: OPC->_int = OPA->_int - OPB->_int; break; case OP_SUB_IF: OPC->_int = OPA->_int - (int) OPB->_float; break; case OP_SUB_FI: OPC->_float = OPA->_float - (float) OPB->_int; break; case OP_MUL_I: OPC->_int = OPA->_int * OPB->_int; break; case OP_MUL_IF: OPC->_int = OPA->_int * (int) OPB->_float; break; case OP_MUL_FI: OPC->_float = OPA->_float * (float) OPB->_int; break; case OP_MUL_VI: OPC->vector[0] = (float) OPB->_int * OPA->vector[0]; OPC->vector[1] = (float) OPB->_int * OPA->vector[1]; OPC->vector[2] = (float) OPB->_int * OPA->vector[2]; break; case OP_DIV_VF: { float temp = 1.0f / OPB->_float; OPC->vector[0] = temp * OPA->vector[0]; OPC->vector[1] = temp * OPA->vector[1]; OPC->vector[2] = temp * OPA->vector[2]; } break; case OP_DIV_I: OPC->_int = OPA->_int / OPB->_int; break; case OP_DIV_IF: OPC->_int = OPA->_int / (int) OPB->_float; break; case OP_DIV_FI: OPC->_float = OPA->_float / (float) OPB->_int; break; case OP_CONV_IF: OPC->_float = OPA->_int; break; case OP_CONV_FI: OPC->_int = OPA->_float; break; case OP_BITAND_I: OPC->_int = OPA->_int & OPB->_int; break; case OP_BITOR_I: OPC->_int = OPA->_int | OPB->_int; break; case OP_BITAND_IF: OPC->_int = OPA->_int & (int) OPB->_float; break; case OP_BITOR_IF: OPC->_int = OPA->_int | (int) OPB->_float; break; case OP_BITAND_FI: OPC->_float = (int) OPA->_float & OPB->_int; break; case OP_BITOR_FI: OPC->_float = (int) OPA->_float | OPB->_int; break; case OP_GE_I: OPC->_float = OPA->_int >= OPB->_int; break; case OP_LE_I: OPC->_float = OPA->_int <= OPB->_int; break; case OP_GT_I: OPC->_float = OPA->_int > OPB->_int; break; case OP_LT_I: OPC->_float = OPA->_int < OPB->_int; break; case OP_AND_I: OPC->_float = OPA->_int && OPB->_int; break; case OP_OR_I: OPC->_float = OPA->_int || OPB->_int; break; case OP_GE_IF: OPC->_float = (float) OPA->_int >= OPB->_float; break; case OP_LE_IF: OPC->_float = (float) OPA->_int <= OPB->_float; break; case OP_GT_IF: OPC->_float = (float) OPA->_int > OPB->_float; break; case OP_LT_IF: OPC->_float = (float) OPA->_int < OPB->_float; break; case OP_AND_IF: OPC->_float = (float) OPA->_int && OPB->_float; break; case OP_OR_IF: OPC->_float = (float) OPA->_int || OPB->_float; break; case OP_GE_FI: OPC->_float = OPA->_float >= (float) OPB->_int; break; case OP_LE_FI: OPC->_float = OPA->_float <= (float) OPB->_int; break; case OP_GT_FI: OPC->_float = OPA->_float > (float) OPB->_int; break; case OP_LT_FI: OPC->_float = OPA->_float < (float) OPB->_int; break; case OP_AND_FI: OPC->_float = OPA->_float && (float) OPB->_int; break; case OP_OR_FI: OPC->_float = OPA->_float || (float) OPB->_int; break; case OP_NOT_I: OPC->_float = !OPA->_int; break; case OP_EQ_I: OPC->_float = OPA->_int == OPB->_int; break; case OP_EQ_IF: OPC->_float = (float) OPA->_int == OPB->_float; break; case OP_EQ_FI: OPC->_float = OPA->_float == (float) OPB->_int; break; case OP_NE_I: OPC->_float = OPA->_int != OPB->_int; break; case OP_NE_IF: OPC->_float = (float) OPA->_int != OPB->_float; break; case OP_NE_FI: OPC->_float = OPA->_float != (float) OPB->_int; break; case OP_STORE_I: OPB->_int = OPA->_int; break; case OP_STOREP_I: if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int + 4 > pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an out of bounds edict\n"); return; } if (pr_boundscheck->int_val && (OPB->_int % pr->pr_edict_size < ((byte *) & (*pr->edicts)->v - (byte *) *pr->edicts))) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an engine edict field\n"); return; } ptr = (eval_t *) ((byte *) *pr->edicts + OPB->_int); ptr->_int = OPA->_int; break; case OP_LOAD_I: if (pr_boundscheck->int_val && (OPA->edict < 0 || OPA->edict >= pr->pr_edictareasize)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an out of bounds edict number\n"); return; } if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int >= pr->progs->entityfields)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an invalid field in an edict\n"); return; } ed = PROG_TO_EDICT (pr, OPA->edict); OPC->_int = ((eval_t *) ((int *) &ed->v + OPB->_int))->_int; break; case OP_GSTOREP_I: case OP_GSTOREP_F: case OP_GSTOREP_ENT: case OP_GSTOREP_FLD: // integers case OP_GSTOREP_S: case OP_GSTOREP_FNC: // pointers if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int >= pr->pr_globaldefs)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an invalid indexed global\n"); return; } pr->pr_globals[OPB->_int] = OPA->_float; break; case OP_GSTOREP_V: if (pr_boundscheck->int_val && (OPB->_int < 0 || OPB->_int + 2 >= pr->pr_globaldefs)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to write to an invalid indexed global\n"); return; } pr->pr_globals[OPB->_int] = OPA->vector[0]; pr->pr_globals[OPB->_int + 1] = OPA->vector[1]; pr->pr_globals[OPB->_int + 2] = OPA->vector[2]; break; case OP_GADDRESS: i = OPA->_int + (int) OPB->_float; if (pr_boundscheck->int_val && (i < 0 || i >= pr->pr_globaldefs)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to address an out of bounds global\n"); return; } OPC->_float = pr->pr_globals[i]; break; case OP_GLOAD_I: case OP_GLOAD_F: case OP_GLOAD_FLD: case OP_GLOAD_ENT: case OP_GLOAD_S: case OP_GLOAD_FNC: if (pr_boundscheck->int_val && (OPA->_int < 0 || OPA->_int >= pr->pr_globaldefs)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an invalid indexed global\n"); return; } OPC->_float = pr->pr_globals[OPA->_int]; break; case OP_GLOAD_V: if (pr_boundscheck->int_val && (OPA->_int < 0 || OPA->_int + 2 >= pr->pr_globaldefs)) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs attempted to read an invalid indexed global\n"); return; } OPC->vector[0] = pr->pr_globals[OPA->_int]; OPC->vector[1] = pr->pr_globals[OPA->_int + 1]; OPC->vector[2] = pr->pr_globals[OPA->_int + 2]; break; case OP_BOUNDCHECK: if (OPA->_int < 0 || OPA->_int >= st->b) { pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Progs boundcheck failed at line number %d, value is < 0 or >= %d\n", st->b, st->c); return; } break; */ default: pr->pr_xstatement = st - pr->pr_statements; PR_RunError (pr, "Bad opcode %i", st->op); } } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() static void SV_SendEffect (sizebuf_t *sb, int idx) { qboolean DoTest; vec3_t TestO1, Diff; float Size, TestDistance; int i, count; if (sb == &sv.reliable_datagram && sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorClear(TestO1); TestDistance = 0; switch (sv.Effects[idx].type) { case CE_RAIN: case CE_SNOW: DoTest = false; break; case CE_FOUNTAIN: DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[idx].ef.Quake.origin, TestO1); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_GRAVITYWELL: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_BONESHARD: case CE_BONESHRAPNEL: VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1); TestDistance = 600; break; case CE_CHUNK: VectorCopy(sv.Effects[idx].ef.Chunk.origin, TestO1); TestDistance = 600; break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } if (!DoTest) count = 1; else { count = svs.maxclients; TestDistance = (float)TestDistance * sv_ce_scale.value; TestDistance *= TestDistance; } for (i = 0 ; i < count ; i++) { if (DoTest) { if (svs.clients[i].active) { sb = &svs.clients[i].datagram; VectorSubtract(svs.clients[i].edict->v.origin, TestO1, Diff); Size = (Diff[0]*Diff[0]) + (Diff[1]*Diff[1]) + (Diff[2]*Diff[2]); if (Size > TestDistance) continue; if (sv_ce_max_size.value > 0 && sb->cursize > sv_ce_max_size.value) continue; } else continue; } MSG_WriteByte (sb, svc_start_effect); MSG_WriteByte (sb, idx); MSG_WriteByte (sb, sv.Effects[idx].type); switch (sv.Effects[idx].type) { case CE_RAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.color); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.count); MSG_WriteFloat(sb, sv.Effects[idx].ef.Rain.wait); break; case CE_SNOW: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.flags); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.count); //MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.veer); break; case CE_FOUNTAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[2]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[0]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[1]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Fountain.color); MSG_WriteByte(sb, sv.Effects[idx].ef.Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.framelength); /* smoke frame is a mission pack thing only. */ if (sv_protocol > PROTOCOL_RAVEN_111) MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.frame); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_FLOOR_EXPLOSION3: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.skinnum); break; case CE_BONESHARD: case CE_BONESHRAPNEL: MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[2]); break; case CE_GRAVITYWELL: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.RD.color); MSG_WriteFloat(sb, sv.Effects[idx].ef.RD.lifetime); break; case CE_CHUNK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.type); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.numChunks); // Con_Printf ("Adding %d chunks on server...\n", sv.Effects[idx].Chunk.numChunks); break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_ParseEffect (sizebuf_t *sb) { int idx; byte effect; effect = G_FLOAT(OFS_PARM0); for (idx = 0 ; idx < MAX_EFFECTS ; idx++) { if (!sv.Effects[idx].type || (sv.Effects[idx].expire_time && sv.Effects[idx].expire_time <= sv.time)) break; } if (idx >= MAX_EFFECTS) { PR_RunError ("MAX_EFFECTS reached"); return; } // Con_Printf("Effect #%d\n", idx); memset(&sv.Effects[idx], 0, sizeof(struct EffectT)); sv.Effects[idx].type = effect; G_FLOAT(OFS_RETURN) = idx; switch (effect) { case CE_RAIN: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Rain.min_org); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Rain.max_org); VectorCopy(G_VECTOR(OFS_PARM3), sv.Effects[idx].ef.Rain.e_size); VectorCopy(G_VECTOR(OFS_PARM4), sv.Effects[idx].ef.Rain.dir); sv.Effects[idx].ef.Rain.color = G_FLOAT(OFS_PARM5); sv.Effects[idx].ef.Rain.count = G_FLOAT(OFS_PARM6); sv.Effects[idx].ef.Rain.wait = G_FLOAT(OFS_PARM7); sv.Effects[idx].ef.Rain.next_time = 0; break; case CE_SNOW: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Rain.min_org); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Rain.max_org); sv.Effects[idx].ef.Rain.flags = G_FLOAT(OFS_PARM3); VectorCopy(G_VECTOR(OFS_PARM4), sv.Effects[idx].ef.Rain.dir); sv.Effects[idx].ef.Rain.count = G_FLOAT(OFS_PARM5); //sv.Effects[idx].Rain.veer = G_FLOAT(OFS_PARM6); //sv.Effects[idx].Rain.wait = 0.10; sv.Effects[idx].ef.Rain.next_time = 0; break; case CE_FOUNTAIN: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Fountain.pos); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Fountain.angle); VectorCopy(G_VECTOR(OFS_PARM3), sv.Effects[idx].ef.Fountain.movedir); sv.Effects[idx].ef.Fountain.color = G_FLOAT(OFS_PARM4); sv.Effects[idx].ef.Fountain.cnt = G_FLOAT(OFS_PARM5); break; case CE_QUAKE: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Quake.origin); sv.Effects[idx].ef.Quake.radius = G_FLOAT(OFS_PARM2); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Smoke.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Smoke.velocity); sv.Effects[idx].ef.Smoke.framelength = G_FLOAT(OFS_PARM3); sv.Effects[idx].ef.Smoke.frame = 0; sv.Effects[idx].expire_time = sv.time + 1; break; case CE_ACID_MUZZFL: case CE_FLAMESTREAM: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: /* mission pack */ VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Smoke.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Smoke.velocity); sv.Effects[idx].ef.Smoke.framelength = 0.05; sv.Effects[idx].ef.Smoke.frame = G_FLOAT(OFS_PARM3); sv.Effects[idx].expire_time = sv.time + 1; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_FLOOR_EXPLOSION3: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Smoke.origin); sv.Effects[idx].expire_time = sv.time + 1; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Flash.origin); sv.Effects[idx].expire_time = sv.time + 1; break; case CE_RIDER_DEATH: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.RD.origin); break; case CE_GRAVITYWELL: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.RD.origin); sv.Effects[idx].ef.RD.color = G_FLOAT(OFS_PARM2); sv.Effects[idx].ef.RD.lifetime = G_FLOAT(OFS_PARM3); break; case CE_TELEPORTERPUFFS: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Teleporter.origin); sv.Effects[idx].expire_time = sv.time + 1; break; case CE_TELEPORTERBODY: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Teleporter.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Teleporter.velocity[0]); sv.Effects[idx].ef.Teleporter.skinnum = G_FLOAT(OFS_PARM3); sv.Effects[idx].expire_time = sv.time + 1; break; case CE_BONESHARD: case CE_BONESHRAPNEL: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Missile.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Missile.velocity); VectorCopy(G_VECTOR(OFS_PARM3), sv.Effects[idx].ef.Missile.angle); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[idx].ef.Missile.avelocity); sv.Effects[idx].expire_time = sv.time + 10; break; case CE_CHUNK: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[idx].ef.Chunk.origin); sv.Effects[idx].ef.Chunk.type = G_FLOAT(OFS_PARM2); VectorCopy(G_VECTOR(OFS_PARM3), sv.Effects[idx].ef.Chunk.srcVel); sv.Effects[idx].ef.Chunk.numChunks = G_FLOAT(OFS_PARM4); sv.Effects[idx].expire_time = sv.time + 3; break; default: PR_RunError ("%s: bad type", __thisfunc__); } SV_SendEffect(sb, idx); }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_LoadEffects(FILE *FH) { int index,Total,count; // Since the map is freshly loaded, clear out any effects as a result of // the loading SV_ClearEffects(); fscanf(FH,"Effects: %d\n",&Total); for(count=0;count<Total;count++) { fscanf(FH,"Effect: %d ",&index); fscanf(FH,"%d %f: ",&sv.Effects[index].type,&sv.Effects[index].expire_time); switch(sv.Effects[index].type) { case CE_RAIN: fscanf(FH, "%f ", &sv.Effects[index].Rain.min_org[0]); fscanf(FH, "%f ", &sv.Effects[index].Rain.min_org[1]); fscanf(FH, "%f ", &sv.Effects[index].Rain.min_org[2]); fscanf(FH, "%f ", &sv.Effects[index].Rain.max_org[0]); fscanf(FH, "%f ", &sv.Effects[index].Rain.max_org[1]); fscanf(FH, "%f ", &sv.Effects[index].Rain.max_org[2]); fscanf(FH, "%f ", &sv.Effects[index].Rain.e_size[0]); fscanf(FH, "%f ", &sv.Effects[index].Rain.e_size[1]); fscanf(FH, "%f ", &sv.Effects[index].Rain.e_size[2]); fscanf(FH, "%f ", &sv.Effects[index].Rain.dir[0]); fscanf(FH, "%f ", &sv.Effects[index].Rain.dir[1]); fscanf(FH, "%f ", &sv.Effects[index].Rain.dir[2]); fscanf(FH, "%d ", &sv.Effects[index].Rain.color); fscanf(FH, "%d ", &sv.Effects[index].Rain.count); fscanf(FH, "%f\n", &sv.Effects[index].Rain.wait); break; case CE_FOUNTAIN: fscanf(FH, "%f ", &sv.Effects[index].Fountain.pos[0]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.pos[1]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.pos[2]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.angle[0]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.angle[1]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.angle[2]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.movedir[0]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.movedir[1]); fscanf(FH, "%f ", &sv.Effects[index].Fountain.movedir[2]); fscanf(FH, "%d ", &sv.Effects[index].Fountain.color); fscanf(FH, "%d\n", &sv.Effects[index].Fountain.cnt); break; case CE_QUAKE: fscanf(FH, "%f ", &sv.Effects[index].Quake.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Quake.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Quake.origin[2]); fscanf(FH, "%f\n", &sv.Effects[index].Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_ACID_MUZZFL: case CE_FLAMESTREAM: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: fscanf(FH, "%f ", &sv.Effects[index].Smoke.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.velocity[0]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.velocity[1]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.velocity[2]); fscanf(FH, "%f\n", &sv.Effects[index].Smoke.framelength); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FBOOM: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_BOMB: fscanf(FH, "%f ", &sv.Effects[index].Smoke.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Smoke.origin[1]); fscanf(FH, "%f\n", &sv.Effects[index].Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: fscanf(FH, "%f ", &sv.Effects[index].Flash.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Flash.origin[1]); fscanf(FH, "%f\n", &sv.Effects[index].Flash.origin[2]); break; case CE_RIDER_DEATH: fscanf(FH, "%f ", &sv.Effects[index].RD.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].RD.origin[1]); fscanf(FH, "%f\n", &sv.Effects[index].RD.origin[2]); break; case CE_TELEPORTERPUFFS: fscanf(FH, "%f ", &sv.Effects[index].Teleporter.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Teleporter.origin[1]); fscanf(FH, "%f\n", &sv.Effects[index].Teleporter.origin[2]); break; case CE_TELEPORTERBODY: fscanf(FH, "%f ", &sv.Effects[index].Teleporter.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Teleporter.origin[1]); fscanf(FH, "%f\n", &sv.Effects[index].Teleporter.origin[2]); break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.avelocity[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.avelocity[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.avelocity[2]); break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.velocity[2]); break; case CE_DEATHBUBBLES: fscanf(FH, "%f ", &sv.Effects[index].Bubble.offset[0]); fscanf(FH, "%f ", &sv.Effects[index].Bubble.offset[1]); fscanf(FH, "%f ", &sv.Effects[index].Bubble.offset[2]); fscanf(FH, "%f ", &sv.Effects[index].Bubble.owner); fscanf(FH, "%f ", &sv.Effects[index].Bubble.count); break; case CE_HWDRILLA: fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[0]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[1]); fscanf(FH, "%f ", &sv.Effects[index].Missile.angle[2]); fscanf(FH, "%f ", &sv.Effects[index].Missile.speed); break; case CE_SCARABCHAIN: fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Chain.owner); fscanf(FH, "%f ", &sv.Effects[index].Chain.material); fscanf(FH, "%f ", &sv.Effects[index].Chain.tag); break; case CE_HWSHEEPINATOR: case CE_HWXBOWSHOOT: fscanf(FH, "%f ", &sv.Effects[index].Xbow.origin[5][0]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.origin[5][1]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.origin[5][2]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.angle[0]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.angle[1]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.angle[2]); fscanf(FH, "%f ", &sv.Effects[index].Xbow.bolts); fscanf(FH, "%f ", &sv.Effects[index].Xbow.activebolts); fscanf(FH, "%f ", &sv.Effects[index].Xbow.turnedbolts); break; case CE_TRIPMINESTILL: case CE_TRIPMINE: fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[0]); fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[1]); fscanf(FH, "%f ", &sv.Effects[index].Chain.origin[2]); fscanf(FH, "%f ", &sv.Effects[index].Chain.velocity[0]); fscanf(FH, "%f ", &sv.Effects[index].Chain.velocity[1]); fscanf(FH, "%f ", &sv.Effects[index].Chain.velocity[2]); break; default: PR_RunError ("SV_SaveEffect: bad type"); break; } } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_ParseEffect(sizebuf_t *sb) { int index; byte effect; effect = G_FLOAT(OFS_PARM0); for(index=0;index<MAX_EFFECTS;index++) if (!sv.Effects[index].type || (sv.Effects[index].expire_time && sv.Effects[index].expire_time <= sv.time)) break; if (index >= MAX_EFFECTS) { PR_RunError ("MAX_EFFECTS reached"); return; } // Con_Printf("Effect #%d\n",index); memset(&sv.Effects[index],0,sizeof(struct EffectT)); sv.Effects[index].type = effect; G_FLOAT(OFS_RETURN) = index; switch(effect) { case CE_RAIN: VectorCopy(G_VECTOR(OFS_PARM1),sv.Effects[index].Rain.min_org); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Rain.max_org); VectorCopy(G_VECTOR(OFS_PARM3),sv.Effects[index].Rain.e_size); VectorCopy(G_VECTOR(OFS_PARM4),sv.Effects[index].Rain.dir); sv.Effects[index].Rain.color = G_FLOAT(OFS_PARM5); sv.Effects[index].Rain.count = G_FLOAT(OFS_PARM6); sv.Effects[index].Rain.wait = G_FLOAT(OFS_PARM7); sv.Effects[index].Rain.next_time = 0; break; case CE_FOUNTAIN: VectorCopy(G_VECTOR(OFS_PARM1),sv.Effects[index].Fountain.pos); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Fountain.angle); VectorCopy(G_VECTOR(OFS_PARM3),sv.Effects[index].Fountain.movedir); sv.Effects[index].Fountain.color = G_FLOAT(OFS_PARM4); sv.Effects[index].Fountain.cnt = G_FLOAT(OFS_PARM5); break; case CE_QUAKE: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Quake.origin); sv.Effects[index].Quake.radius = G_FLOAT(OFS_PARM2); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_RIPPLE: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Smoke.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[index].Smoke.velocity); sv.Effects[index].Smoke.framelength = G_FLOAT(OFS_PARM3); sv.Effects[index].expire_time = sv.time + 1; break; case CE_ACID_MUZZFL: case CE_FLAMESTREAM: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Smoke.origin); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[index].Smoke.velocity); sv.Effects[index].Smoke.framelength = 0.05; sv.Effects[index].Smoke.frame = G_FLOAT(OFS_PARM3); sv.Effects[index].expire_time = sv.time + 1; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Smoke.origin); sv.Effects[index].expire_time = sv.time + 1; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Flash.origin); sv.Effects[index].expire_time = sv.time + 1; break; case CE_RIDER_DEATH: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].RD.origin); break; case CE_TELEPORTERPUFFS: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Teleporter.origin); sv.Effects[index].expire_time = sv.time + 1; break; case CE_TELEPORTERBODY: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Teleporter.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Teleporter.velocity[0]); sv.Effects[index].Teleporter.skinnum = G_FLOAT(OFS_PARM3); sv.Effects[index].expire_time = sv.time + 1; break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Missile.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Missile.velocity); VectorCopy(G_VECTOR(OFS_PARM3),sv.Effects[index].Missile.angle); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Missile.avelocity); sv.Effects[index].expire_time = sv.time + 10; break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: case CE_HWRAVENPOWER: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Missile.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Missile.velocity); sv.Effects[index].expire_time = sv.time + 10; break; case CE_DEATHBUBBLES: VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[index].Bubble.offset); sv.Effects[index].Bubble.owner = G_EDICTNUM(OFS_PARM1); sv.Effects[index].Bubble.count = G_FLOAT(OFS_PARM3); sv.Effects[index].expire_time = sv.time + 30; break; case CE_HWDRILLA: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Missile.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Missile.angle); sv.Effects[index].Missile.speed = G_FLOAT(OFS_PARM3); sv.Effects[index].expire_time = sv.time + 10; break; case CE_TRIPMINESTILL: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Chain.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Chain.velocity); sv.Effects[index].expire_time = sv.time + 70; break; case CE_TRIPMINE: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Chain.origin); VectorCopy(G_VECTOR(OFS_PARM2),sv.Effects[index].Chain.velocity); sv.Effects[index].expire_time = sv.time + 10; break; case CE_SCARABCHAIN: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Chain.origin); sv.Effects[index].Chain.owner = G_EDICTNUM(OFS_PARM2); sv.Effects[index].Chain.material = G_INT(OFS_PARM3); sv.Effects[index].Chain.tag = G_INT(OFS_PARM4); sv.Effects[index].Chain.state = 0; sv.Effects[index].expire_time = sv.time + 15; break; case CE_HWSHEEPINATOR: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[0]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[1]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[2]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[3]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[4]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[5]); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[index].Xbow.angle); sv.Effects[index].Xbow.bolts = 5; sv.Effects[index].Xbow.activebolts = 31; sv.Effects[index].Xbow.randseed = 0; sv.Effects[index].Xbow.turnedbolts = 0; sv.Effects[index].expire_time = sv.time + 7; break; case CE_HWXBOWSHOOT: VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[0]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[1]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[2]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[3]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[4]); VectorCopy(G_VECTOR(OFS_PARM1), sv.Effects[index].Xbow.origin[5]); VectorCopy(G_VECTOR(OFS_PARM2), sv.Effects[index].Xbow.angle); sv.Effects[index].Xbow.bolts = G_FLOAT(OFS_PARM3); sv.Effects[index].Xbow.randseed = G_FLOAT(OFS_PARM4); sv.Effects[index].Xbow.turnedbolts = 0; if (sv.Effects[index].Xbow.bolts == 3) { sv.Effects[index].Xbow.activebolts = 7; } else { sv.Effects[index].Xbow.activebolts = 31; } sv.Effects[index].expire_time = sv.time + 15; break; default: // Sys_Error ("SV_ParseEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); } SV_SendEffect(sb,index); }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_SendEffect(sizebuf_t *sb, int index) { qboolean DoTest; vec3_t TestO; int TestDistance; int i; if (sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorCopy(vec3_origin, TestO); switch(sv.Effects[index].type) { case CE_HWSHEEPINATOR: case CE_HWXBOWSHOOT: VectorCopy(sv.Effects[index].Xbow.origin[5], TestO); TestDistance = 900; break; case CE_SCARABCHAIN: VectorCopy(sv.Effects[index].Chain.origin, TestO); TestDistance = 900; break; case CE_TRIPMINE: VectorCopy(sv.Effects[index].Chain.origin, TestO); // DoTest = false; break; //ACHTUNG!!!!!!! setting DoTest to false here does not insure that effect will be sent to everyone! case CE_TRIPMINESTILL: TestDistance = 10000; DoTest = false; break; case CE_RAIN: TestDistance = 10000; DoTest = false; break; case CE_FOUNTAIN: TestDistance = 10000; DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[index].Quake.origin, TestO); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_DEATHBUBBLES: if (sv.Effects[index].Bubble.owner < 0 || sv.Effects[index].Bubble.owner >= sv.num_edicts) { return; } VectorCopy(PROG_TO_EDICT(sv.Effects[index].Bubble.owner)->v.origin, TestO); TestDistance = 400; break; case CE_HWDRILLA: case CE_BONESHARD: case CE_BONESHRAPNEL: case CE_HWBONEBALL: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 900; break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 600; break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } MSG_WriteByte (&sv.multicast, svc_start_effect); MSG_WriteByte (&sv.multicast, index); MSG_WriteByte (&sv.multicast, sv.Effects[index].type); switch(sv.Effects[index].type) { case CE_RAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.color); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.count); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Rain.wait); break; case CE_FOUNTAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[1]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Fountain.color); MSG_WriteByte(&sv.multicast, sv.Effects[index].Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.framelength); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.skinnum); break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[2]); break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: case CE_HWRAVENPOWER: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); break; case CE_HWDRILLA: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Missile.speed); break; case CE_DEATHBUBBLES: MSG_WriteShort(&sv.multicast, sv.Effects[index].Bubble.owner); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[0]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[1]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.count); break; case CE_SCARABCHAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Chain.owner+sv.Effects[index].Chain.material); MSG_WriteByte(&sv.multicast, sv.Effects[index].Chain.tag); break; case CE_TRIPMINESTILL: case CE_TRIPMINE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[2]); break; case CE_HWSHEEPINATOR: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; case CE_HWXBOWSHOOT: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); // MSG_WriteFloat(&sv.multicast, sv.Effects[index].Xbow.angle[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.bolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.randseed); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } if (sb) { SZ_Write (sb, sv.multicast.data, sv.multicast.cursize); SZ_Clear (&sv.multicast); } else { if (DoTest) { SV_Multicast (TestO, MULTICAST_PVS_R); } else { SV_Multicast (TestO, MULTICAST_ALL_R); } sv.Effects[index].client_list = clients_multicast; } }
/* ==================== PR_ExecuteProgram ==================== */ void PR_ExecuteProgram (func_t fnum) { eval_t *a, *b, *c; int s; dstatement_t *st; dfunction_t *f, *newf; int runaway; int i; edict_t *ed; int exitdepth; eval_t *ptr; // 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes start char *funcname; char *remaphint; // 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes end if (!fnum || fnum >= progs->numfunctions) { if (pr_global_struct->self) ED_Print (PROG_TO_EDICT(pr_global_struct->self)); Host_Error ("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; runaway = RUNAWAY; //was 100000; pr_trace = false; // make a stack frame exitdepth = pr_depth; s = PR_EnterFunction (f); while (1) { s++; // next statement pr_xstatement = s; pr_xfunction->profile++; st = &pr_statements[s]; a = (eval_t *)&pr_globals[st->a]; b = (eval_t *)&pr_globals[st->b]; c = (eval_t *)&pr_globals[st->c]; if (!--runaway) PR_RunError ("runaway loop error"); if (runaway < RUNAWAY - RUNAWAY_STEP + 1 && runaway % RUNAWAY_STEP == 0) { Con_Printf ("PR_ExecuteProgram: runaway loop %d\n", runaway / RUNAWAY_STEP); SCR_UpdateScreen (); // Force screen update S_ClearBuffer (); // Avoid looping sounds } if (pr_trace) PR_PrintStatement (st); switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !pr_strings[a->string]; break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; //================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) PR_RunError ("assignment to world entity"); c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; //================== case OP_IFNOT: if (!a->_int) s += st->b - 1; // offset the s++ break; case OP_IF: if (a->_int) s += st->b - 1; // offset the s++ break; case OP_GOTO: s += st->a - 1; // offset the s++ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr_argc = st->op - OP_CALL0; if (!a->function) PR_RunError ("NULL function"); newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // negative statements are built in functions i = -newf->first_statement; // 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes start if ( (i >= pr_numbuiltins)||(pr_builtins[i] == pr_ebfs_builtins[0].function) ) { funcname = pr_strings + newf->s_name; if (pr_builtin_remap.value) { remaphint = NULL; } else { remaphint = "Try \"builtin remapping\" by setting PR_BUILTIN_REMAP to 1\n"; } PR_RunError ("Bad builtin call number %i for %s\n", i, funcname, remaphint); } // 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes end pr_builtins[i] (); break; } s = PR_EnterFunction (newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[st->a]; pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; s = PR_LeaveFunction (); if (pr_depth == exitdepth) return; // all done break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); #ifdef FPS_20 ed->v.nextthink = pr_global_struct->time + 0.05; #else ed->v.nextthink = pr_global_struct->time + 0.1; #endif if (a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; default: PR_RunError ("Bad opcode %i", st->op); } } }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_SaveEffects (FILE *FH) { int idx, count; for (idx = count = 0 ; idx < MAX_EFFECTS ; idx++) { if (sv.Effects[idx].type) count++; } fprintf(FH, "Effects: %d\n", count); for (idx = count = 0 ; idx < MAX_EFFECTS ; idx++) { if ( ! sv.Effects[idx].type ) continue; fprintf(FH, "Effect: %d %d %f: ", idx, sv.Effects[idx].type, sv.Effects[idx].expire_time); switch (sv.Effects[idx].type) { case CE_RAIN: fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.min_org[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.min_org[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.min_org[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.max_org[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.max_org[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.max_org[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.e_size[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.e_size[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.e_size[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.dir[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.dir[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Rain.dir[2]); fprintf(FH, "%d ", sv.Effects[idx].ef.Rain.color); fprintf(FH, "%d ", sv.Effects[idx].ef.Rain.count); fprintf(FH, "%f\n", sv.Effects[idx].ef.Rain.wait); break; case CE_FOUNTAIN: fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.pos[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.pos[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.pos[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.angle[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.angle[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.angle[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.movedir[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.movedir[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Fountain.movedir[2]); fprintf(FH, "%d ", sv.Effects[idx].ef.Fountain.color); fprintf(FH, "%d\n", sv.Effects[idx].ef.Fountain.cnt); break; case CE_QUAKE: fprintf(FH, "%f ", sv.Effects[idx].ef.Quake.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Quake.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Quake.origin[2]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_ACID_MUZZFL: case CE_FLAMESTREAM: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.origin[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.velocity[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.velocity[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.velocity[2]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Smoke.framelength); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Smoke.origin[1]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: fprintf(FH, "%f ", sv.Effects[idx].ef.Flash.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Flash.origin[1]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Flash.origin[2]); break; case CE_RIDER_DEATH: fprintf(FH, "%f ", sv.Effects[idx].ef.RD.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.RD.origin[1]); fprintf(FH, "%f\n", sv.Effects[idx].ef.RD.origin[2]); break; case CE_TELEPORTERPUFFS: fprintf(FH, "%f ", sv.Effects[idx].ef.Teleporter.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Teleporter.origin[1]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Teleporter.origin[2]); break; case CE_TELEPORTERBODY: fprintf(FH, "%f ", sv.Effects[idx].ef.Teleporter.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Teleporter.origin[1]); fprintf(FH, "%f\n", sv.Effects[idx].ef.Teleporter.origin[2]); break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.avelocity[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.avelocity[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.avelocity[2]); break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.velocity[2]); break; case CE_DEATHBUBBLES: fprintf(FH, "%f ", sv.Effects[idx].ef.Bubble.offset[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Bubble.offset[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Bubble.offset[2]); fprintf(FH, "%d ", sv.Effects[idx].ef.Bubble.owner); fprintf(FH, "%d ", sv.Effects[idx].ef.Bubble.count); break; case CE_HWDRILLA: fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.origin[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.angle[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Missile.speed); break; case CE_SCARABCHAIN: fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[2]); fprintf(FH, "%d ", sv.Effects[idx].ef.Chain.owner); fprintf(FH, "%d ", sv.Effects[idx].ef.Chain.material); fprintf(FH, "%d ", sv.Effects[idx].ef.Chain.tag); break; case CE_HWSHEEPINATOR: case CE_HWXBOWSHOOT: fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.origin[5][0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.origin[5][1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.origin[5][2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.angle[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.angle[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Xbow.angle[2]); fprintf(FH, "%d ", sv.Effects[idx].ef.Xbow.bolts); fprintf(FH, "%d ", sv.Effects[idx].ef.Xbow.activebolts); fprintf(FH, "%d ", sv.Effects[idx].ef.Xbow.turnedbolts); break; case CE_TRIPMINESTILL: case CE_TRIPMINE: fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.origin[2]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.velocity[0]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.velocity[1]); fprintf(FH, "%f ", sv.Effects[idx].ef.Chain.velocity[2]); break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } } }
void PR_ExecuteProgram(func_t fnum) { int i; int s; eval_t *a, *b, *c; eval_t *ptr; dstatement_t *st; dfunction_t *f, *newf; int runaway; edict_t *ed; int exitdepth; int startFrame; int endFrame; float val; int case_type=-1; float switch_float; if(!fnum || fnum >= progs->numfunctions) { if(pr_global_struct->self) { ED_Print(PROG_TO_EDICT(pr_global_struct->self)); } Host_Error("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; runaway = 100000; pr_trace = false; exitdepth = pr_depth; s = EnterFunction(f); #ifdef TIMESNAP_ACTIVE ProgsTimer(); // Init #endif while (1) { s++; // Next statement st = &pr_statements[s]; a = (eval_t *)&pr_globals[(unsigned short)st->a]; b = (eval_t *)&pr_globals[(unsigned short)st->b]; c = (eval_t *)&pr_globals[(unsigned short)st->c]; if(!--runaway) { PR_RunError("runaway loop error"); } #ifndef TIMESNAP_ACTIVE pr_xfunction->profile++; #endif pr_xstatement = s; if(pr_trace) { PrintStatement(st); } switch(st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !pr_strings[a->string]; break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_MULSTORE_F: // f *= f b->_float *= a->_float; break; case OP_MULSTORE_V: // v *= f b->vector[0] *= a->_float; b->vector[1] *= a->_float; b->vector[2] *= a->_float; break; case OP_MULSTOREP_F: // e.f *= f ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->_float = (ptr->_float *= a->_float); break; case OP_MULSTOREP_V: // e.v *= f ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->vector[0] = (ptr->vector[0] *= a->_float); c->vector[0] = (ptr->vector[1] *= a->_float); c->vector[0] = (ptr->vector[2] *= a->_float); break; case OP_DIVSTORE_F: // f /= f b->_float /= a->_float; break; case OP_DIVSTOREP_F: // e.f /= f ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->_float = (ptr->_float /= a->_float); break; case OP_ADDSTORE_F: // f += f b->_float += a->_float; break; case OP_ADDSTORE_V: // v += v b->vector[0] += a->vector[0]; b->vector[1] += a->vector[1]; b->vector[2] += a->vector[2]; break; case OP_ADDSTOREP_F: // e.f += f ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->_float = (ptr->_float += a->_float); break; case OP_ADDSTOREP_V: // e.v += v ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->vector[0] = (ptr->vector[0] += a->vector[0]); c->vector[1] = (ptr->vector[1] += a->vector[1]); c->vector[2] = (ptr->vector[2] += a->vector[2]); break; case OP_SUBSTORE_F: // f -= f b->_float -= a->_float; break; case OP_SUBSTORE_V: // v -= v b->vector[0] -= a->vector[0]; b->vector[1] -= a->vector[1]; b->vector[2] -= a->vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->_float = (ptr->_float -= a->_float); break; case OP_SUBSTOREP_V: // e.v -= v ptr = (eval_t *)((byte *)sv.edicts+b->_int); c->vector[0] = (ptr->vector[0] -= a->vector[0]); c->vector[1] = (ptr->vector[1] -= a->vector[1]); c->vector[2] = (ptr->vector[2] -= a->vector[2]); break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if(ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } c->_int = (byte *)((int *)&ed->v + b->_int)-(byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v+b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_FETCH_GBL_F: case OP_FETCH_GBL_S: case OP_FETCH_GBL_E: case OP_FETCH_GBL_FNC: i = (int)b->_float; if(i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a + i]; c->_int = a->_int; break; case OP_FETCH_GBL_V: i = (int)b->_float; if(i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a +((int)b->_float)*3]; c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_IFNOT: if(!a->_int) { s += st->b-1; // -1 to offset the s++ } break; case OP_IF: if(a->_int) { s += st->b-1; // -1 to offset the s++ } break; case OP_GOTO: s += st->a-1; // -1 to offset the s++ break; case OP_CALL8: case OP_CALL7: case OP_CALL6: case OP_CALL5: case OP_CALL4: case OP_CALL3: case OP_CALL2: // Copy second arg to shared space VectorCopy(c->vector, G_VECTOR(OFS_PARM1)); case OP_CALL1: // Copy first arg to shared space VectorCopy(b->vector, G_VECTOR(OFS_PARM0)); case OP_CALL0: pr_argc = st->op-OP_CALL0; if(!a->function) { PR_RunError("NULL function"); } newf = &pr_functions[a->function]; if(newf->first_statement < 0) { // Built-in function i = -newf->first_statement; if(i >= pr_numbuiltins) { PR_RunError("Bad builtin call number"); } pr_builtins[i](); break; } // Normal function #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = EnterFunction(newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a]; pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short)st->a+1]; pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short)st->a+2]; #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = LeaveFunction(); if(pr_depth == exitdepth) { // Done return; } break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); /* Id 1.07 changes #ifdef FPS_20 ed->v.nextthink = pr_global_struct->time + 0.05; #else ed->v.nextthink = pr_global_struct->time + 0.1; #endif */ ed->v.nextthink = pr_global_struct->time+HX_FRAME_TIME; if(a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; case OP_CSTATE: // Cycle state ed = PROG_TO_EDICT(pr_global_struct->self); ed->v.nextthink = pr_global_struct->time+HX_FRAME_TIME; ed->v.think = pr_xfunction-pr_functions; pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if(startFrame <= endFrame) { // Increment if(ed->v.frame < startFrame || ed->v.frame > endFrame) { ed->v.frame = startFrame; break; } ed->v.frame++; if(ed->v.frame > endFrame) { pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; } // Decrement if(ed->v.frame > startFrame || ed->v.frame < endFrame) { ed->v.frame = startFrame; break; } ed->v.frame--; if(ed->v.frame < endFrame) { pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; case OP_CWSTATE: // Cycle weapon state ed = PROG_TO_EDICT(pr_global_struct->self); ed->v.nextthink = pr_global_struct->time+HX_FRAME_TIME; ed->v.think = pr_xfunction-pr_functions; pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if(startFrame <= endFrame) { // Increment if(ed->v.weaponframe < startFrame || ed->v.weaponframe > endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe++; if(ed->v.weaponframe > endFrame) { pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; } // Decrement if(ed->v.weaponframe > startFrame || ed->v.weaponframe < endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe--; if(ed->v.weaponframe < endFrame) { pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; case OP_THINKTIME: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if(ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } ed->v.nextthink = pr_global_struct->time+b->_float; break; case OP_BITSET: // f (+) f b->_float = (int)b->_float | (int)a->_float; break; case OP_BITSETP: // e.f (+) f ptr = (eval_t *)((byte *)sv.edicts+b->_int); ptr->_float = (int)ptr->_float | (int)a->_float; break; case OP_BITCLR: // f (-) f b->_float = (int)b->_float & ~((int)a->_float); break; case OP_BITCLRP: // e.f (-) f ptr = (eval_t *)((byte *)sv.edicts+b->_int); ptr->_float = (int)ptr->_float & ~((int)a->_float); break; case OP_RAND0: val = rand()*(1.0/RAND_MAX);//(rand()&0x7fff)/((float)0x7fff); G_FLOAT(OFS_RETURN) = val; break; case OP_RAND1: val = rand()*(1.0/RAND_MAX)*a->_float; G_FLOAT(OFS_RETURN) = val; break; case OP_RAND2: if(a->_float < b->_float) { val = a->_float+(rand()*(1.0/RAND_MAX) *(b->_float-a->_float)); } else { val = b->_float+(rand()*(1.0/RAND_MAX) *(a->_float-b->_float)); } G_FLOAT(OFS_RETURN) = val; break; case OP_RANDV0: val = rand()*(1.0/RAND_MAX); G_FLOAT(OFS_RETURN+0) = val; val = rand()*(1.0/RAND_MAX); G_FLOAT(OFS_RETURN+1) = val; val = rand()*(1.0/RAND_MAX); G_FLOAT(OFS_RETURN+2) = val; break; case OP_RANDV1: val = rand()*(1.0/RAND_MAX)*a->vector[0]; G_FLOAT(OFS_RETURN+0) = val; val = rand()*(1.0/RAND_MAX)*a->vector[1]; G_FLOAT(OFS_RETURN+1) = val; val = rand()*(1.0/RAND_MAX)*a->vector[2]; G_FLOAT(OFS_RETURN+2) = val; break; case OP_RANDV2: for(i = 0; i < 3; i++) { if(a->vector[i] < b->vector[i]) { val = a->vector[i]+(rand()*(1.0/RAND_MAX) *(b->vector[i]-a->vector[i])); } else { val = b->vector[i]+(rand()*(1.0/RAND_MAX) *(a->vector[i]-b->vector[i])); } G_FLOAT(OFS_RETURN+i) = val; } break; case OP_SWITCH_F: case_type = SWITCH_F; switch_float = a->_float; s += st->b-1; // -1 to offset the s++ break; case OP_SWITCH_V: PR_RunError("switch v not done yet!"); break; case OP_SWITCH_S: PR_RunError("switch s not done yet!"); break; case OP_SWITCH_E: PR_RunError("switch e not done yet!"); break; case OP_SWITCH_FNC: PR_RunError("switch fnc not done yet!"); break; case OP_CASERANGE: if (case_type!=SWITCH_F) PR_RunError("caserange f****d!"); if((switch_float >= a->_float) && (switch_float <= b->_float)) { s += st->c-1; // -1 to offset the s++ } break; case OP_CASE: switch (case_type) { case SWITCH_F: if(switch_float == a->_float) { s += st->b-1; // -1 to offset the s++ } break; case SWITCH_V: case SWITCH_S: case SWITCH_E: case SWITCH_FNC: PR_RunError("case not done yet!"); break; default: PR_RunError("f****d case!"); } break; default: PR_RunError("Bad opcode %i", st->op); } } }
/* PR_ExecuteProgram The interpretation main loop */ VISIBLE void PR_ExecuteProgram (progs_t * pr, func_t fnum) { int exitdepth, profile, startprofile; pr_uint_t pointer; dstatement_t *st; edict_t *ed; pr_type_t *ptr; pr_type_t old_val = {0}, *watch = 0; // make a stack frame exitdepth = pr->pr_depth; startprofile = profile = 0; Sys_PushSignalHook (signal_hook, pr); if (!PR_CallFunction (pr, fnum)) { // called a builtin instead of progs code Sys_PopSignalHook (); return; } st = pr->pr_statements + pr->pr_xstatement; if (pr->watch) { watch = pr->watch; old_val = *watch; } while (1) { pr_type_t *op_a, *op_b, *op_c; st++; ++pr->pr_xstatement; if (pr->pr_xstatement != st - pr->pr_statements) PR_RunError (pr, "internal error"); if (++profile > 1000000 && !pr->no_exec_limit) { PR_RunError (pr, "runaway loop error"); } op_a = pr->pr_globals + st->a; op_b = pr->pr_globals + st->b; op_c = pr->pr_globals + st->c; if (pr->pr_trace) PR_PrintStatement (pr, st, 1); switch (st->op) { case OP_ADD_F: OPC.float_var = OPA.float_var + OPB.float_var; break; case OP_ADD_V: VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var); break; case OP_ADD_Q: QuatAdd (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_ADD_S: OPC.string_var = PR_CatStrings (pr, PR_GetString (pr, OPA.string_var), PR_GetString (pr, OPB.string_var)); break; case OP_SUB_F: OPC.float_var = OPA.float_var - OPB.float_var; break; case OP_SUB_V: VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var); break; case OP_SUB_Q: QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_MUL_F: OPC.float_var = OPA.float_var * OPB.float_var; break; case OP_MUL_V: OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); break; case OP_MUL_FV: { // avoid issues with the likes of x = x.x * x; // makes for faster code, too float scale = OPA.float_var; VectorScale (OPB.vector_var, scale, OPC.vector_var); } break; case OP_MUL_VF: { // avoid issues with the likes of x = x * x.x; // makes for faster code, too float scale = OPB.float_var; VectorScale (OPA.vector_var, scale, OPC.vector_var); } break; case OP_MUL_Q: QuatMult (OPA.quat_var, OPB.quat_var, OPC.quat_var); break; case OP_MUL_QV: QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); break; case OP_MUL_FQ: { // avoid issues with the likes of x = x.s * x; // makes for faster code, too float scale = OPA.float_var; QuatScale (OPB.quat_var, scale, OPC.quat_var); } break; case OP_MUL_QF: { // avoid issues with the likes of x = x * x.s; // makes for faster code, too float scale = OPB.float_var; QuatScale (OPA.quat_var, scale, OPC.quat_var); } break; case OP_CONJ_Q: QuatConj (OPA.quat_var, OPC.quat_var); break; case OP_DIV_F: OPC.float_var = OPA.float_var / OPB.float_var; break; case OP_BITAND: OPC.float_var = (int) OPA.float_var & (int) OPB.float_var; break; case OP_BITOR: OPC.float_var = (int) OPA.float_var | (int) OPB.float_var; break; case OP_BITXOR_F: OPC.float_var = (int) OPA.float_var ^ (int) OPB.float_var; break; case OP_BITNOT_F: OPC.float_var = ~ (int) OPA.float_var; break; case OP_SHL_F: OPC.float_var = (int) OPA.float_var << (int) OPB.float_var; break; case OP_SHR_F: OPC.float_var = (int) OPA.float_var >> (int) OPB.float_var; break; case OP_SHL_I: OPC.integer_var = OPA.integer_var << OPB.integer_var; break; case OP_SHR_I: OPC.integer_var = OPA.integer_var >> OPB.integer_var; break; case OP_SHR_U: OPC.uinteger_var = OPA.uinteger_var >> OPB.integer_var; break; case OP_GE_F: OPC.float_var = OPA.float_var >= OPB.float_var; break; case OP_LE_F: OPC.float_var = OPA.float_var <= OPB.float_var; break; case OP_GT_F: OPC.float_var = OPA.float_var > OPB.float_var; break; case OP_LT_F: OPC.float_var = OPA.float_var < OPB.float_var; break; case OP_AND: // OPA and OPB have to be float for -0.0 OPC.integer_var = FNZ (OPA) && FNZ (OPB); break; case OP_OR: // OPA and OPB have to be float for -0.0 OPC.integer_var = FNZ (OPA) || FNZ (OPB); break; case OP_NOT_F: OPC.integer_var = !FNZ (OPA); break; case OP_NOT_V: OPC.integer_var = VectorIsZero (OPA.vector_var); break; case OP_NOT_Q: OPC.integer_var = QuatIsZero (OPA.quat_var); break; case OP_NOT_S: OPC.integer_var = !OPA.string_var || !*PR_GetString (pr, OPA.string_var); break; case OP_NOT_FN: OPC.integer_var = !OPA.func_var; break; case OP_NOT_ENT: OPC.integer_var = !OPA.entity_var; break; case OP_EQ_F: OPC.integer_var = OPA.float_var == OPB.float_var; break; case OP_EQ_V: OPC.integer_var = VectorCompare (OPA.vector_var, OPB.vector_var); break; case OP_EQ_Q: OPC.integer_var = QuatCompare (OPA.quat_var, OPB.quat_var); break; case OP_EQ_E: OPC.integer_var = OPA.integer_var == OPB.integer_var; break; case OP_EQ_FN: OPC.integer_var = OPA.func_var == OPB.func_var; break; case OP_NE_F: OPC.integer_var = OPA.float_var != OPB.float_var; break; case OP_NE_V: OPC.integer_var = !VectorCompare (OPA.vector_var, OPB.vector_var); break; case OP_NE_Q: OPC.integer_var = !QuatCompare (OPA.quat_var, OPB.quat_var); break; case OP_LE_S: case OP_GE_S: case OP_LT_S: case OP_GT_S: case OP_NE_S: case OP_EQ_S: { int cmp = strcmp (PR_GetString (pr, OPA.string_var), PR_GetString (pr, OPB.string_var)); switch (st->op) { case OP_LE_S: cmp = (cmp <= 0); break; case OP_GE_S: cmp = (cmp >= 0); break; case OP_LT_S: cmp = (cmp < 0); break; case OP_GT_S: cmp = (cmp > 0); break; case OP_NE_S: break; case OP_EQ_S: cmp = !cmp; break; default: break; } OPC.integer_var = cmp; } break; case OP_NE_E: OPC.integer_var = OPA.integer_var != OPB.integer_var; break; case OP_NE_FN: OPC.integer_var = OPA.func_var != OPB.func_var; break; // ================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FN: // pointers case OP_STORE_I: case OP_STORE_P: OPB.integer_var = OPA.integer_var; break; case OP_STORE_V: VectorCopy (OPA.vector_var, OPB.vector_var); break; case OP_STORE_Q: QuatCopy (OPA.quat_var, OPB.quat_var); break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FN: // pointers case OP_STOREP_I: case OP_STOREP_P: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREP_V: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREP_Q: pointer = OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; case OP_ADDRESS: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to address an out " "of bounds edict"); if (OPA.entity_var == 0 && pr->null_bad) PR_RunError (pr, "assignment to world entity"); if (OPB.uinteger_var >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to address an " "invalid field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); OPC.integer_var = &ed->v[OPB.integer_var] - pr->pr_globals; break; case OP_ADDRESS_VOID: case OP_ADDRESS_F: case OP_ADDRESS_V: case OP_ADDRESS_Q: case OP_ADDRESS_S: case OP_ADDRESS_ENT: case OP_ADDRESS_FLD: case OP_ADDRESS_FN: case OP_ADDRESS_I: case OP_ADDRESS_P: OPC.integer_var = st->a; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FN: case OP_LOAD_I: case OP_LOAD_P: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); OPC.integer_var = ed->v[OPB.integer_var].integer_var; break; case OP_LOAD_V: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 2 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); break; case OP_LOAD_Q: if (pr_boundscheck->int_val) { if (OPA.entity_var < 0 || OPA.entity_var >= pr->pr_edictareasize) PR_RunError (pr, "Progs attempted to read an out of " "bounds edict number"); if (OPB.uinteger_var + 3 >= pr->progs->entityfields) PR_RunError (pr, "Progs attempted to read an invalid " "field in an edict"); } ed = PROG_TO_EDICT (pr, OPA.entity_var); memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC)); break; case OP_LOADB_F: case OP_LOADB_S: case OP_LOADB_ENT: case OP_LOADB_FLD: case OP_LOADB_FN: case OP_LOADB_I: case OP_LOADB_P: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; OPC.integer_var = ptr->integer_var; break; case OP_LOADB_V: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (ptr->vector_var, OPC.vector_var); break; case OP_LOADB_Q: pointer = OPA.integer_var + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; case OP_LOADBI_F: case OP_LOADBI_S: case OP_LOADBI_ENT: case OP_LOADBI_FLD: case OP_LOADBI_FN: case OP_LOADBI_I: case OP_LOADBI_P: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; OPC.integer_var = ptr->integer_var; break; case OP_LOADBI_V: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (ptr->vector_var, OPC.vector_var); break; case OP_LOADBI_Q: pointer = OPA.integer_var + (short) st->b; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (ptr->quat_var, OPC.quat_var); break; case OP_LEA: pointer = OPA.integer_var + OPB.integer_var; OPC.integer_var = pointer; break; case OP_LEAI: pointer = OPA.integer_var + (short) st->b; OPC.integer_var = pointer; break; case OP_STOREB_F: case OP_STOREB_S: case OP_STOREB_ENT: case OP_STOREB_FLD: case OP_STOREB_FN: case OP_STOREB_I: case OP_STOREB_P: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREB_V: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREB_Q: pointer = OPB.integer_var + OPC.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; case OP_STOREBI_F: case OP_STOREBI_S: case OP_STOREBI_ENT: case OP_STOREBI_FLD: case OP_STOREBI_FN: case OP_STOREBI_I: case OP_STOREBI_P: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; ptr->integer_var = OPA.integer_var; break; case OP_STOREBI_V: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; VectorCopy (OPA.vector_var, ptr->vector_var); break; case OP_STOREBI_Q: pointer = OPB.integer_var + (short) st->c; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; QuatCopy (OPA.quat_var, ptr->quat_var); break; // ================== case OP_IFNOT: if (!OPA.integer_var) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IF: if (OPA.integer_var) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFBE: if (OPA.integer_var <= 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFB: if (OPA.integer_var < 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFAE: if (OPA.integer_var >= 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_IFA: if (OPA.integer_var > 0) { pr->pr_xstatement += (short)st->b - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; } break; case OP_GOTO: pr->pr_xstatement += (short)st->a - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_JUMP: if (pr_boundscheck->int_val && (OPA.uinteger_var >= pr->progs->numstatements)) { PR_RunError (pr, "Invalid jump destination"); } pr->pr_xstatement = OPA.uinteger_var - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_JUMPB: pointer = st->a + OPB.integer_var; if (pr_boundscheck->int_val) { PR_BoundsCheck (pr, pointer, ev_integer); } ptr = pr->pr_globals + pointer; pointer = ptr->integer_var; if (pr_boundscheck->int_val && (pointer >= pr->progs->numstatements)) { PR_RunError (pr, "Invalid jump destination"); } pr->pr_xstatement = pointer - 1; // offset the st++ st = pr->pr_statements + pr->pr_xstatement; break; case OP_RCALL2: case OP_RCALL3: case OP_RCALL4: case OP_RCALL5: case OP_RCALL6: case OP_RCALL7: case OP_RCALL8: pr->pr_params[1] = &OPC; goto op_rcall; case OP_RCALL1: pr->pr_params[1] = pr->pr_real_params[1]; op_rcall: pr->pr_params[0] = &OPB; pr->pr_argc = st->op - OP_RCALL1 + 1; goto op_call; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: PR_RESET_PARAMS (pr); pr->pr_argc = st->op - OP_CALL0; op_call: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; PR_CallFunction (pr, OPA.func_var); st = pr->pr_statements + pr->pr_xstatement; break; case OP_DONE: case OP_RETURN: if (!st->a) memset (&R_INT (pr), 0, pr->pr_param_size * sizeof (OPA)); else if (&R_INT (pr) != &OPA.integer_var) memcpy (&R_INT (pr), &OPA, pr->pr_param_size * sizeof (OPA)); // fallthrough case OP_RETURN_V: pr->pr_xfunction->profile += profile - startprofile; startprofile = profile; PR_LeaveFunction (pr); st = pr->pr_statements + pr->pr_xstatement; if (pr->pr_depth == exitdepth) { if (pr->pr_trace && pr->pr_depth <= pr->pr_trace_depth) pr->pr_trace = false; Sys_PopSignalHook (); return; // all done } break; case OP_STATE: ed = PROG_TO_EDICT (pr, *pr->globals.self); ed->v[pr->fields.nextthink].float_var = *pr->globals.time + 0.1; ed->v[pr->fields.frame].float_var = OPA.float_var; ed->v[pr->fields.think].func_var = OPB.func_var; break; case OP_STATE_F: ed = PROG_TO_EDICT (pr, *pr->globals.self); ed->v[pr->fields.nextthink].float_var = *pr->globals.time + OPC.float_var; ed->v[pr->fields.frame].float_var = OPA.float_var; ed->v[pr->fields.think].func_var = OPB.func_var; break; case OP_ADD_I: OPC.integer_var = OPA.integer_var + OPB.integer_var; break; case OP_SUB_I: OPC.integer_var = OPA.integer_var - OPB.integer_var; break; case OP_MUL_I: OPC.integer_var = OPA.integer_var * OPB.integer_var; break; /* case OP_DIV_VF: { float temp = 1.0f / OPB.float_var; VectorScale (OPA.vector_var, temp, OPC.vector_var); } break; */ case OP_DIV_I: OPC.integer_var = OPA.integer_var / OPB.integer_var; break; case OP_MOD_I: OPC.integer_var = OPA.integer_var % OPB.integer_var; break; case OP_MOD_F: OPC.float_var = (int) OPA.float_var % (int) OPB.float_var; break; case OP_CONV_IF: OPC.float_var = OPA.integer_var; break; case OP_CONV_FI: OPC.integer_var = OPA.float_var; break; case OP_BITAND_I: OPC.integer_var = OPA.integer_var & OPB.integer_var; break; case OP_BITOR_I: OPC.integer_var = OPA.integer_var | OPB.integer_var; break; case OP_BITXOR_I: OPC.integer_var = OPA.integer_var ^ OPB.integer_var; break; case OP_BITNOT_I: OPC.integer_var = ~OPA.integer_var; break; case OP_GE_I: case OP_GE_P: OPC.integer_var = OPA.integer_var >= OPB.integer_var; break; case OP_GE_U: OPC.integer_var = OPA.uinteger_var >= OPB.uinteger_var; break; case OP_LE_I: case OP_LE_P: OPC.integer_var = OPA.integer_var <= OPB.integer_var; break; case OP_LE_U: OPC.integer_var = OPA.uinteger_var <= OPB.uinteger_var; break; case OP_GT_I: case OP_GT_P: OPC.integer_var = OPA.integer_var > OPB.integer_var; break; case OP_GT_U: OPC.integer_var = OPA.uinteger_var > OPB.uinteger_var; break; case OP_LT_I: case OP_LT_P: OPC.integer_var = OPA.integer_var < OPB.integer_var; break; case OP_LT_U: OPC.integer_var = OPA.uinteger_var < OPB.uinteger_var; break; case OP_AND_I: OPC.integer_var = OPA.integer_var && OPB.integer_var; break; case OP_OR_I: OPC.integer_var = OPA.integer_var || OPB.integer_var; break; case OP_NOT_I: case OP_NOT_P: OPC.integer_var = !OPA.integer_var; break; case OP_EQ_I: case OP_EQ_P: OPC.integer_var = OPA.integer_var == OPB.integer_var; break; case OP_NE_I: case OP_NE_P: OPC.integer_var = OPA.integer_var != OPB.integer_var; break; case OP_MOVEI: memmove (&OPC, &OPA, st->b * 4); break; case OP_MOVEP: if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, OPC.integer_var, OPB.uinteger_var); PR_BoundsCheckSize (pr, OPA.integer_var, OPB.uinteger_var); } memmove (pr->pr_globals + OPC.integer_var, pr->pr_globals + OPA.integer_var, OPB.uinteger_var * 4); break; case OP_MOVEPI: if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, OPC.integer_var, st->b); PR_BoundsCheckSize (pr, OPA.integer_var, st->b); } memmove (pr->pr_globals + OPC.integer_var, pr->pr_globals + OPA.integer_var, st->b * 4); break; // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* case OP_BOUNDCHECK: if (OPA.integer_var < 0 || OPA.integer_var >= st->b) { PR_RunError (pr, "Progs boundcheck failed at line number " "%d, value is < 0 or >= %d", st->b, st->c); } break; */ default: PR_RunError (pr, "Bad opcode %i", st->op); } if (watch && watch->integer_var != old_val.integer_var && (!pr->wp_conditional || watch->integer_var == pr->wp_val.integer_var)) PR_RunError (pr, "watchpoint hit: %d -> %d", old_val.integer_var, watch->integer_var); } }
/* ==================== PR_ExecuteProgram ==================== */ void PR_ExecuteProgram (func_t fnum) { eval_t *a, *b, *c; int s; dstatement_t *st; dfunction_t *f, *newf; int runaway; int i; edict_t *ed; int exitdepth; eval_t *ptr; if (!fnum || fnum >= progs->numfunctions) { if (pr_global_struct->self) ED_Print (PROG_TO_EDICT(pr_global_struct->self)); Host_Error ("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; runaway = 100000; pr_trace = false; // make a stack frame exitdepth = pr_depth; s = PR_EnterFunction (f); while (1) { s++; // next statement st = &pr_statements[s]; a = (eval_t *)&pr_globals[st->a]; b = (eval_t *)&pr_globals[st->b]; c = (eval_t *)&pr_globals[st->c]; if (!--runaway) PR_RunError ("runaway loop error"); pr_xfunction->profile++; pr_xstatement = s; if (pr_trace) PR_PrintStatement (st); switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !pr_strings[a->string]; break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; //================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) PR_RunError ("assignment to world entity"); c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; //================== case OP_IFNOT: if (!a->_int) s += st->b - 1; // offset the s++ break; case OP_IF: if (a->_int) s += st->b - 1; // offset the s++ break; case OP_GOTO: s += st->a - 1; // offset the s++ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr_argc = st->op - OP_CALL0; if (!a->function) PR_RunError ("NULL function"); newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // negative statements are built in functions i = -newf->first_statement; if (i >= pr_numbuiltins) PR_RunError ("Bad builtin call number"); pr_builtins[i] (); break; } s = PR_EnterFunction (newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[st->a]; pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; s = PR_LeaveFunction (); if (pr_depth == exitdepth) return; // all done break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); #ifdef FPS_20 ed->v.nextthink = pr_global_struct->time + 0.05; #else ed->v.nextthink = pr_global_struct->time + 0.1; #endif if (a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; default: PR_RunError ("Bad opcode %i", st->op); } } }
void PR_ExecuteProgram (func_t fnum) { eval_t *ptr, *a, *b, *c; float *vecptr; dstatement_t *st; dfunction_t *f, *newf; edict_t *ed; int jump_ofs; int exitdepth; int profile, startprofile; /* switch/case support: */ int case_type = -1; float switch_float = 0; if (!fnum || fnum >= progs->numfunctions) { if (*sv_globals.self) { ED_Print(PROG_TO_EDICT(*sv_globals.self)); } Host_Error("%s: NULL function", __thisfunc__); } f = &pr_functions[fnum]; pr_trace = false; exitdepth = pr_depth; st = &pr_statements[EnterFunction(f)]; startprofile = profile = 0; while (1) { st++; /* next statement */ a = OPA; b = OPB; c = OPC; if (++profile > 100000) { pr_xstatement = st - pr_statements; PR_RunError("runaway loop error"); } if (pr_trace) { PrintStatement(st); } switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0] * b->vector[0] + a->vector[1] * b->vector[1] + a->vector[2] * b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !*PR_GetString(a->string); break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_MULSTORE_F: // f *= f b->_float *= a->_float; break; case OP_MULSTORE_V: // v *= f b->vector[0] *= a->_float; b->vector[1] *= a->_float; b->vector[2] *= a->_float; break; case OP_MULSTOREP_F: // e.f *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float *= a->_float); break; case OP_MULSTOREP_V: // e.v *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] *= a->_float); c->vector[0] = (ptr->vector[1] *= a->_float); c->vector[0] = (ptr->vector[2] *= a->_float); break; case OP_DIVSTORE_F: // f /= f b->_float /= a->_float; break; case OP_DIVSTOREP_F: // e.f /= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float /= a->_float); break; case OP_ADDSTORE_F: // f += f b->_float += a->_float; break; case OP_ADDSTORE_V: // v += v b->vector[0] += a->vector[0]; b->vector[1] += a->vector[1]; b->vector[2] += a->vector[2]; break; case OP_ADDSTOREP_F: // e.f += f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float += a->_float); break; case OP_ADDSTOREP_V: // e.v += v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] += a->vector[0]); c->vector[1] = (ptr->vector[1] += a->vector[1]); c->vector[2] = (ptr->vector[2] += a->vector[2]); break; case OP_SUBSTORE_F: // f -= f b->_float -= a->_float; break; case OP_SUBSTORE_V: // v -= v b->vector[0] -= a->vector[0]; b->vector[1] -= a->vector[1]; b->vector[2] -= a->vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float -= a->_float); break; case OP_SUBSTOREP_V: // e.v -= v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] -= a->vector[0]); c->vector[1] = (ptr->vector[1] -= a->vector[1]); c->vector[2] = (ptr->vector[2] -= a->vector[2]); break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { pr_xstatement = st - pr_statements; PR_RunError("assignment to world entity"); } c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif ptr = (eval_t *)((int *)&ed->v + b->_int); c->_int = ptr->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif ptr = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = ptr->vector[0]; c->vector[1] = ptr->vector[1]; c->vector[2] = ptr->vector[2]; break; case OP_FETCH_GBL_F: case OP_FETCH_GBL_S: case OP_FETCH_GBL_E: case OP_FETCH_GBL_FNC: { int i = (int)b->_float; if (i < 0 || i > G_INT(st->a - 1)) { pr_xstatement = st - pr_statements; PR_RunError("array index out of bounds: %d", i); } ptr = (eval_t *)&pr_globals[st->a + i]; c->_int = ptr->_int; } break; case OP_FETCH_GBL_V: { int i = (int)b->_float; if (i < 0 || i > G_INT(st->a - 1)) { pr_xstatement = st - pr_statements; PR_RunError("array index out of bounds: %d", i); } ptr = (eval_t *)&pr_globals[st->a + (i * 3)]; c->vector[0] = ptr->vector[0]; c->vector[1] = ptr->vector[1]; c->vector[2] = ptr->vector[2]; } break; case OP_IFNOT: if (!a->_int) { /* Pa3PyX: a, b, and c used to be signed shorts for progs v6, * now they are signed ints. The problem is, they were used * as signed sometimes and as unsigned other times - most of * the time they were used as unsigned with an explicit cast * in PR_ExecuteProgram(). When we convert the old progs to * to the new format in PR_ConvertOldStmts(), we zero-extend * them instead of sign-extending them for that reason: if we * sign-extend them, most of the code will not work - we will * have negative array offsets in PR_ExecuteProgram(), among * other things. Note that they are cast to unsigned short * in PR_ConvertOldStmts() prior to assigning them to what is * now int. There are a few instances where these shorts are * used as signed as in the case below where negative offsets * are needed. Since we now have a zero-extended number in a, * b, and c, we must change it back to signed short, so that * when it is added with and assigned to an int, the result * ends up sign-extended and we get a proper negative offset, * if there is one. */ jump_ofs = st->b; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ } break; case OP_IF: if (a->_int) { jump_ofs = st->b; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ } break; case OP_GOTO: jump_ofs = st->a; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ break; case OP_CALL8: case OP_CALL7: case OP_CALL6: case OP_CALL5: case OP_CALL4: case OP_CALL3: case OP_CALL2: // Copy second arg to shared space vecptr = G_VECTOR(OFS_PARM1); VectorCopy(c->vector, vecptr); case OP_CALL1: // Copy first arg to shared space vecptr = G_VECTOR(OFS_PARM0); VectorCopy(b->vector, vecptr); case OP_CALL0: pr_xfunction->profile += profile - startprofile; startprofile = profile; pr_xstatement = st - pr_statements; pr_argc = st->op - OP_CALL0; if (!a->function) { PR_RunError("NULL function"); } newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // Built-in function int i = -newf->first_statement; if (i >= pr_numbuiltins) { PR_RunError("Bad builtin call number %d", i); } pr_builtins[i](); break; } // Normal function st = &pr_statements[EnterFunction(newf)]; break; case OP_DONE: case OP_RETURN: { float *retptr = &pr_globals[OFS_RETURN]; float *valptr = &pr_globals[st->a]; pr_xfunction->profile += profile - startprofile; startprofile = profile; pr_xstatement = st - pr_statements; *retptr++ = *valptr++; *retptr++ = *valptr++; *retptr = *valptr; st = &pr_statements[LeaveFunction()]; if (pr_depth == exitdepth) { // Done return; } } break; case OP_STATE: ed = PROG_TO_EDICT(*sv_globals.self); /* Id 1.07 changes #ifdef FPS_20 ed->v.nextthink = *sv_globals.time + 0.05; #else ed->v.nextthink = *sv_globals.time + 0.1; #endif */ ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME; ed->v.frame = a->_float; ed->v.think = b->function; break; case OP_CSTATE: // Cycle state { int startFrame, endFrame; ed = PROG_TO_EDICT(*sv_globals.self); ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; *sv_globals.cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.frame < startFrame || ed->v.frame > endFrame) { ed->v.frame = startFrame; } else { ed->v.frame++; if (ed->v.frame > endFrame) { *sv_globals.cycle_wrapped = true; ed->v.frame = startFrame; } } } else { // Decrement if (ed->v.frame > startFrame || ed->v.frame < endFrame) { ed->v.frame = startFrame; } else { ed->v.frame--; if (ed->v.frame < endFrame) { *sv_globals.cycle_wrapped = true; ed->v.frame = startFrame; } } } } break; case OP_CWSTATE: // Cycle weapon state { int startFrame, endFrame; ed = PROG_TO_EDICT(*sv_globals.self); ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; *sv_globals.cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.weaponframe < startFrame || ed->v.weaponframe > endFrame) { ed->v.weaponframe = startFrame; } else { ed->v.weaponframe++; if (ed->v.weaponframe > endFrame) { *sv_globals.cycle_wrapped = true; ed->v.weaponframe = startFrame; } } } else { // Decrement if (ed->v.weaponframe > startFrame || ed->v.weaponframe < endFrame) { ed->v.weaponframe = startFrame; } else { ed->v.weaponframe--; if (ed->v.weaponframe < endFrame) { *sv_globals.cycle_wrapped = true; ed->v.weaponframe = startFrame; } } } } break; case OP_THINKTIME: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { pr_xstatement = st - pr_statements; PR_RunError("assignment to world entity"); } ed->v.nextthink = *sv_globals.time + b->_float; break; case OP_BITSET: // f (+) f b->_float = (int)b->_float | (int)a->_float; break; case OP_BITSETP: // e.f (+) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float | (int)a->_float; break; case OP_BITCLR: // f (-) f b->_float = (int)b->_float & ~((int)a->_float); break; case OP_BITCLRP: // e.f (-) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float & ~((int)a->_float); break; case OP_RAND0: { float val; val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN) = val; } break; case OP_RAND1: { float val; val = rand() * (1.0 / RAND_MAX) * a->_float; G_FLOAT(OFS_RETURN) = val; } break; case OP_RAND2: { float val; if (a->_float < b->_float) { val = a->_float + (rand() * (1.0 / RAND_MAX) * (b->_float - a->_float)); } else { val = b->_float + (rand() * (1.0 / RAND_MAX) * (a->_float - b->_float)); } G_FLOAT(OFS_RETURN) = val; } break; case OP_RANDV0: { float val; float *retptr = &G_FLOAT(OFS_RETURN); val = rand() * (1.0 / RAND_MAX); *retptr++ = val; val = rand() * (1.0 / RAND_MAX); *retptr++ = val; val = rand() * (1.0 / RAND_MAX); *retptr = val; } break; case OP_RANDV1: { float val; float *retptr = &G_FLOAT(OFS_RETURN); val = rand() * (1.0 / RAND_MAX) * a->vector[0]; *retptr++ = val; val = rand() * (1.0 / RAND_MAX) * a->vector[1]; *retptr++ = val; val = rand() * (1.0 / RAND_MAX) * a->vector[2]; *retptr = val; } break; case OP_RANDV2: { float val; int i; float *retptr = &G_FLOAT(OFS_RETURN); for (i = 0; i < 3; i++) { if (a->vector[i] < b->vector[i]) { val = a->vector[i] + (rand() * (1.0 / RAND_MAX) * (b->vector[i] - a->vector[i])); } else { val = b->vector[i] + (rand() * (1.0 / RAND_MAX) * (a->vector[i] - b->vector[i])); } *retptr++ = val; } } break; case OP_SWITCH_F: case_type = SWITCH_F; switch_float = a->_float; jump_ofs = st->b; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ break; case OP_SWITCH_V: case OP_SWITCH_S: case OP_SWITCH_E: case OP_SWITCH_FNC: pr_xstatement = st - pr_statements; PR_RunError("%s not done yet!", pr_opnames[st->op]); break; case OP_CASERANGE: if (case_type != SWITCH_F) { pr_xstatement = st - pr_statements; PR_RunError("caserange f****d!"); } if ((switch_float >= a->_float) && (switch_float <= b->_float)) { jump_ofs = st->c; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ } break; case OP_CASE: switch (case_type) { case SWITCH_F: if (switch_float == a->_float) { jump_ofs = st->b; if (is_progs_v6) jump_ofs = (signed short)jump_ofs; st += jump_ofs - 1; /* -1 to offset the st++ */ } break; case SWITCH_V: case SWITCH_S: case SWITCH_E: case SWITCH_FNC: pr_xstatement = st - pr_statements; PR_RunError("OP_CASE for %s not done yet!", pr_opnames[case_type + OP_SWITCH_F - SWITCH_F]); break; default: pr_xstatement = st - pr_statements; PR_RunError("f****d case!"); } break; default: pr_xstatement = st - pr_statements; PR_RunError("Bad opcode %i", st->op); } } /* end of while(1) loop */ }
/** Setup the stackframe prior to calling a progs function. Saves all local data the called function will trample on and copies the parameters used by the function into the function's local data space. \param pr pointer to progs_t VM struct \param f pointer to the descriptor for the called function \note Passing a descriptor for a builtin function will result in undefined behavior. */ static void PR_EnterFunction (progs_t *pr, bfunction_t *f) { pr_int_t i, j, c, o; pr_int_t k; pr_int_t count = 0; int size[2] = {0, 0}; long paramofs = 0; long offs; PR_PushFrame (pr); if (f->numparms > 0) { for (i = 0; i < 2 && i < f->numparms; i++) { paramofs += f->parm_size[i]; size[i] = f->parm_size[i]; } count = i; } else if (f->numparms < 0) { for (i = 0; i < 2 && i < -f->numparms - 1; i++) { paramofs += f->parm_size[i]; size[i] = f->parm_size[i]; } for (; i < 2; i++) { paramofs += pr->pr_param_size; size[i] = pr->pr_param_size; } count = i; } for (i = 0; i < count && i < pr->pr_argc; i++) { offs = (pr->pr_params[i] - pr->pr_globals) - f->parm_start; if (offs >= 0 && offs < paramofs) { memcpy (pr->pr_real_params[i], pr->pr_params[i], size[i] * sizeof (pr_type_t)); pr->pr_params[i] = pr->pr_real_params[i]; } } //Sys_Printf("%s:\n", PR_GetString(pr,f->s_name)); pr->pr_xfunction = f; pr->pr_xstatement = f->first_statement - 1; // offset the st++ // save off any locals that the new function steps on c = f->locals; if (pr->localstack_used + c > LOCALSTACK_SIZE) PR_RunError (pr, "PR_EnterFunction: locals stack overflow"); memcpy (&pr->localstack[pr->localstack_used], &pr->pr_globals[f->parm_start], sizeof (pr_type_t) * c); pr->localstack_used += c; if (pr_deadbeef_locals->int_val) for (k = f->parm_start; k < f->parm_start + c; k++) pr->pr_globals[k].integer_var = 0xdeadbeef; // copy parameters o = f->parm_start; if (f->numparms >= 0) { for (i = 0; i < f->numparms; i++) { for (j = 0; j < f->parm_size[i]; j++) { memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j, sizeof (pr_type_t)); o++; } } } else { pr_type_t *argc = &pr->pr_globals[o++]; pr_type_t *argv = &pr->pr_globals[o++]; for (i = 0; i < -f->numparms - 1; i++) { for (j = 0; j < f->parm_size[i]; j++) { memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j, sizeof (pr_type_t)); o++; } } argc->integer_var = pr->pr_argc - i; argv->integer_var = o; if (i < MAX_PARMS) { memcpy (&pr->pr_globals[o], &P_INT (pr, i), (MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t)); } } }