// // A_CounterSwitch // // This powerful codepointer can branch to one of N states // depending on the value of the indicated counter, and it // remains totally safe at all times. If the entire indicated // frame set is not valid, no actions will be taken. // // args[0] : counter # to use // args[1] : DeHackEd number of first frame in consecutive set // args[2] : number of frames in consecutive set // void A_CounterSwitch(Mobj *mo) { int cnum, startstate, numstates; int *counter; cnum = E_ArgAsInt(mo->state->args, 0, 0); startstate = E_ArgAsStateNumNI(mo->state->args, 1, mo); numstates = E_ArgAsInt(mo->state->args, 2, 0) - 1; // get counter if(cnum < 0 || cnum >= NUMMOBJCOUNTERS) return; // invalid counter = &(mo->counters[cnum]); // verify startstate if(startstate < 0) return; // verify last state is < NUMSTATES if(startstate + numstates >= NUMSTATES) return; // verify counter is in range if(*counter < 0 || *counter > numstates) return; // jump! P_SetMobjState(mo, startstate + *counter); }
// // A_CounterJump // // Parameterized codepointer for branching based on comparisons // against a thing's counter values. // // args[0] : state number // args[1] : comparison type // args[2] : immediate value OR counter number // args[3] : counter # to use // void A_CounterJump(Mobj *mo) { bool branch = false; int statenum, checktype, value, cnum; int *counter; statenum = E_ArgAsStateNumNI(mo->state->args, 0, mo); checktype = E_ArgAsKwd(mo->state->args, 1, &cpckwds, 0); value = E_ArgAsInt(mo->state->args, 2, 0); cnum = E_ArgAsInt(mo->state->args, 3, 0); // validate state if(statenum < 0) return; if(cnum < 0 || cnum >= NUMMOBJCOUNTERS) return; // invalid counter = &(mo->counters[cnum]); // 08/02/04: // support getting check value from a counter // if checktype is greater than the last immediate operator, // then the comparison value is actually a counter number if(checktype >= CPC_NUMIMMEDIATE) { // turn it into the corresponding immediate operation checktype -= CPC_NUMIMMEDIATE; if(value < 0 || value >= NUMMOBJCOUNTERS) return; // invalid counter number value = mo->counters[value]; } switch(checktype) { case CPC_LESS: branch = (*counter < value); break; case CPC_LESSOREQUAL: branch = (*counter <= value); break; case CPC_GREATER: branch = (*counter > value); break; case CPC_GREATEROREQUAL: branch = (*counter >= value); break; case CPC_EQUAL: branch = (*counter == value); break; case CPC_NOTEQUAL: branch = (*counter != value); break; case CPC_BITWISEAND: branch = !!(*counter & value); break; default: break; } if(branch) P_SetMobjState(mo, statenum); }
// // A_SetCounter // // Sets the value of the indicated counter variable for the thing. // Can perform numerous operations -- this is more like a virtual // machine than a codepointer ;) // // args[0] : counter # to set // args[1] : value to utilize // args[2] : operation to perform // void A_SetCounter(Mobj *mo) { int cnum, value, specialop; int *counter; cnum = E_ArgAsInt(mo->state->args, 0, 0); value = E_ArgAsInt(mo->state->args, 1, 0); specialop = E_ArgAsKwd(mo->state->args, 2, &cpsetkwds, 0); if(cnum < 0 || cnum >= NUMMOBJCOUNTERS) return; // invalid counter = &(mo->counters[cnum]); switch(specialop) { case CPOP_ASSIGN: *counter = value; break; case CPOP_ADD: *counter += value; break; case CPOP_SUB: *counter -= value; break; case CPOP_MUL: *counter *= value; break; case CPOP_DIV: if(value) // don't divide by zero *counter /= value; break; case CPOP_MOD: if(value > 0) // only allow modulus by positive values *counter %= value; break; case CPOP_AND: *counter &= value; break; case CPOP_ANDNOT: *counter &= ~value; break; // compound and-not operation case CPOP_OR: *counter |= value; break; case CPOP_XOR: *counter ^= value; break; case CPOP_RND: *counter = P_Random(pr_setcounter); break; case CPOP_RNDMOD: if(value > 0) *counter = P_Random(pr_setcounter) % value; break; case CPOP_SHIFTLEFT: *counter <<= value; break; case CPOP_SHIFTRIGHT: *counter >>= value; break; default: break; } }
// // A_SargAttack12 // // DOOM 1.2 Demon attack // haleyjd 07/29/14 // void A_SargAttack12(actionargs_t *actionargs) { Mobj *actor = actionargs->actor; int damage, mod, mul; if(!actor->target) return; mod = E_ArgAsInt(actionargs->args, 0, 10); mul = E_ArgAsInt(actionargs->args, 1, 4); A_FaceTarget(actionargs); damage = ((P_Random(pr_sargattack) % mod) + 1) * mul; P_LineAttack(actor, actor->angle, MELEERANGE, 0, damage); }
// // A_WeaponCtrSwitch // // This powerful codepointer can branch to one of N states // depending on the value of the indicated counter, and it // remains totally safe at all times. If the entire indicated // frame set is not valid, no actions will be taken. // // args[0] : counter # to use // args[1] : DeHackEd number of first frame in consecutive set // args[2] : number of frames in consecutive set // args[3] : psprite to affect (weapon or flash) // void A_WeaponCtrSwitch(Mobj *mo) { int cnum, startstate, numstates, psprnum; int *counter; player_t *player; pspdef_t *pspr; if(!(player = mo->player)) return; pspr = &(player->psprites[player->curpsprite]); cnum = E_ArgAsInt(pspr->state->args, 0, 0); startstate = E_ArgAsStateNumNI(pspr->state->args, 1, NULL); numstates = E_ArgAsInt(pspr->state->args, 2, 0) - 1; psprnum = E_ArgAsKwd(pspr->state->args, 3, &psprkwds, 0); // validate psprite number if(psprnum < 0 || psprnum >= NUMPSPRITES) return; // get counter switch(cnum) { case 0: case 1: case 2: counter = &(player->weaponctrs[player->readyweapon][cnum]); break; default: return; } // verify startstate if(startstate < 0) return; // verify last state is < NUMSTATES if(startstate + numstates >= NUMSTATES) return; // verify counter is in range if(*counter < 0 || *counter > numstates) return; // jump! P_SetPsprite(player, psprnum, startstate + *counter); }
// // A_CopyCounter // // Copies the value of one counter into another. // // args[0] : source counter # // args[1] : destination counter # // void A_CopyCounter(Mobj *mo) { int cnum1, cnum2; int *src, *dest; cnum1 = E_ArgAsInt(mo->state->args, 0, 0); cnum2 = E_ArgAsInt(mo->state->args, 1, 0); if(cnum1 < 0 || cnum1 >= NUMMOBJCOUNTERS) return; // invalid src = &(mo->counters[cnum1]); if(cnum2 < 0 || cnum2 >= NUMMOBJCOUNTERS) return; // invalid dest = &(mo->counters[cnum2]); *dest = *src; }
// // A_SubTics // // Note: was A_DelayGib in Hexen // Parameters: // * args[0] : mode select (0 = random amt, 1 = use args[1]) // * args[1] : if mode == 0, shift amt; if mode == 1, amount to subtract // void A_SubTics(Mobj *actor) { int mode = E_ArgAsInt(actor->state->args, 0, 0); int amt = E_ArgAsInt(actor->state->args, 1, 0); switch(mode) { case 0: actor->tics -= P_Random(pr_subtics) >> amt; break; case 1: actor->tics -= amt; break; default: break; } // cannot set tics to zero, to avoid state cycles. if(actor->tics <= 0) actor->tics = 1; }
// // A_HealthJump // // Parameterized codepointer for branching based on comparisons // against a thing's health. // // args[0] : state number // args[1] : comparison type // args[2] : health value OR counter number // void A_HealthJump(Mobj *mo) { bool branch = false; int statenum, checktype, checkhealth; statenum = E_ArgAsStateNumNI(mo->state->args, 0, mo); checktype = E_ArgAsKwd(mo->state->args, 1, &cpckwds, 0); checkhealth = E_ArgAsInt(mo->state->args, 2, 0); // validate state if(statenum < 0) return; // 08/02/04: // support getting check value from a counter // if checktype is greater than the last immediate operator, // then the checkhealth value is actually a counter number if(checktype >= CPC_NUMIMMEDIATE) { // turn it into the corresponding immediate operation checktype -= CPC_NUMIMMEDIATE; if(checkhealth < 0 || checkhealth >= NUMMOBJCOUNTERS) return; // invalid counter number checkhealth = mo->counters[checkhealth]; } switch(checktype) { case CPC_LESS: branch = (mo->health < checkhealth); break; case CPC_LESSOREQUAL: branch = (mo->health <= checkhealth); break; case CPC_GREATER: branch = (mo->health > checkhealth); break; case CPC_GREATEROREQUAL: branch = (mo->health >= checkhealth); break; case CPC_EQUAL: branch = (mo->health == checkhealth); break; case CPC_NOTEQUAL: branch = (mo->health != checkhealth); break; case CPC_BITWISEAND: branch = !!(mo->health & checkhealth); break; default: break; } if(branch) P_SetMobjState(mo, statenum); }
// // A_WeaponCopyCtr // // Copies the value of one counter into another. // // args[0] : source counter # // args[1] : destination counter # // void A_WeaponCopyCtr(Mobj *mo) { int cnum1, cnum2; int *src, *dest; player_t *player; pspdef_t *pspr; if(!(player = mo->player)) return; pspr = &(player->psprites[player->curpsprite]); cnum1 = E_ArgAsInt(pspr->state->args, 0, 0); cnum2 = E_ArgAsInt(pspr->state->args, 1, 0); switch(cnum1) { case 0: case 1: case 2: src = &(player->weaponctrs[player->readyweapon][cnum1]); break; default: return; } switch(cnum2) { case 0: case 1: case 2: dest = &(player->weaponctrs[player->readyweapon][cnum2]); break; default: return; } *dest = *src; }
// // A_LowerFloorClip // // Note: was A_SerpentLowerHump in Hexen // Parameters: // * args[0] == amount to increase floorclip in eighths of a unit // void A_LowerFloorClip(Mobj *actor) { fixed_t amt = E_ArgAsInt(actor->state->args, 0, 0) * FRACUNIT / 8; actor->floorclip += amt; }
// // A_WeaponCtrOp // // Sets the value of the indicated counter variable for the weapon // using two (possibly the same) counters as operands. // // args[0] : counter operand #1 // args[1] : counter operand #2 // args[2] : counter destination // args[3] : operation to perform // void A_WeaponCtrOp(Mobj *mo) { player_t *player; pspdef_t *pspr; int c_oper1_num; int c_oper2_num; int c_dest_num; int specialop; int *c_oper1, *c_oper2, *c_dest; if(!(player = mo->player)) return; pspr = &(player->psprites[player->curpsprite]); c_oper1_num = E_ArgAsInt(pspr->state->args, 0, 0); c_oper2_num = E_ArgAsInt(pspr->state->args, 1, 0); c_dest_num = E_ArgAsInt(pspr->state->args, 2, 0); specialop = E_ArgAsKwd(pspr->state->args, 3, &weapctropkwds, 0); switch(c_oper1_num) { case 0: case 1: case 2: c_oper1 = &(player->weaponctrs[player->readyweapon][c_oper1_num]); break; default: return; } switch(c_oper2_num) { case 0: case 1: case 2: c_oper2 = &(player->weaponctrs[player->readyweapon][c_oper2_num]); break; default: return; } switch(c_dest_num) { case 0: case 1: case 2: c_dest = &(player->weaponctrs[player->readyweapon][c_dest_num]); break; default: return; } switch(specialop) { case CPOP_ADD: *c_dest = *c_oper1 + *c_oper2; break; case CPOP_SUB: *c_dest = *c_oper1 - *c_oper2; break; case CPOP_MUL: *c_dest = *c_oper1 * *c_oper2; break; case CPOP_DIV: if(c_oper2) // don't divide by zero *c_dest = *c_oper1 / *c_oper2; break; case CPOP_MOD: if(*c_oper2 > 0) // only allow modulus by positive values *c_dest = *c_oper1 % *c_oper2; break; case CPOP_AND: *c_dest = *c_oper1 & *c_oper2; break; case CPOP_OR: *c_dest = *c_oper1 | *c_oper2; break; case CPOP_XOR: *c_dest = *c_oper1 ^ *c_oper2; break; case CPOP_DAMAGE: // do a HITDICE-style calculation if(*c_oper2 > 0) // the modulus must be positive *c_dest = *c_oper1 * ((P_Random(pr_weapsetctr) % *c_oper2) + 1); break; case CPOP_SHIFTLEFT: *c_dest = *c_oper1 << *c_oper2; break; case CPOP_SHIFTRIGHT: *c_dest = *c_oper1 >> *c_oper2; break; // unary operations (c_oper2 is unused for these) case CPOP_ABS: *c_dest = abs(*c_oper1); break; case CPOP_NEGATE: *c_dest = -(*c_oper1); break; case CPOP_NOT: *c_dest = !(*c_oper1); break; case CPOP_INVERT: *c_dest = ~(*c_oper1); break; default: break; } }
// // A_WeaponSetCtr // // Sets the value of the indicated counter variable for the thing. // Can perform numerous operations -- this is more like a virtual // machine than a codepointer ;) // // args[0] : counter # to set // args[1] : value to utilize // args[2] : operation to perform // void A_WeaponSetCtr(Mobj *mo) { int cnum; int value; int specialop; int *counter; player_t *player; pspdef_t *pspr; if(!(player = mo->player)) return; pspr = &(player->psprites[player->curpsprite]); cnum = E_ArgAsInt(pspr->state->args, 0, 0); value = E_ArgAsInt(pspr->state->args, 1, 0); specialop = E_ArgAsKwd(pspr->state->args, 2, &weapsetkwds, 0); switch(cnum) { case 0: case 1: case 2: counter = &(player->weaponctrs[player->readyweapon][cnum]); break; default: return; } switch(specialop) { case CPOP_ASSIGN: *counter = value; break; case CPOP_ADD: *counter += value; break; case CPOP_SUB: *counter -= value; break; case CPOP_MUL: *counter *= value; break; case CPOP_DIV: if(value) // don't divide by zero *counter /= value; break; case CPOP_MOD: if(value > 0) // only allow modulus by positive values *counter %= value; break; case CPOP_AND: *counter &= value; break; case CPOP_ANDNOT: *counter &= ~value; break; // compound and-not operation case CPOP_OR: *counter |= value; break; case CPOP_XOR: *counter ^= value; break; case CPOP_RND: *counter = P_Random(pr_weapsetctr); break; case CPOP_RNDMOD: if(value > 0) *counter = P_Random(pr_weapsetctr) % value; break; case CPOP_SHIFTLEFT: *counter <<= value; break; case CPOP_SHIFTRIGHT: *counter >>= value; break; default: break; } }
// // A_WeaponCtrJump // // Parameterized codepointer for branching based on comparisons // against a weapon's counter values. // // args[0] : state number // args[1] : comparison type // args[2] : immediate value OR counter number // args[3] : counter # to use // args[4] : psprite to affect (weapon or flash) // void A_WeaponCtrJump(Mobj *mo) { bool branch = false; int statenum, checktype, cnum, psprnum; int value, *counter; player_t *player; pspdef_t *pspr; if(!(player = mo->player)) return; pspr = &(player->psprites[player->curpsprite]); statenum = E_ArgAsStateNumNI(pspr->state->args, 0, NULL); checktype = E_ArgAsKwd(pspr->state->args, 1, &weapctrkwds, 0); value = E_ArgAsInt(pspr->state->args, 2, 0); cnum = E_ArgAsInt(pspr->state->args, 3, 0); psprnum = E_ArgAsKwd(pspr->state->args, 4, &psprkwds, 0); // validate state if(statenum < 0) return; // validate psprite number if(psprnum < 0 || psprnum >= NUMPSPRITES) return; switch(cnum) { case 0: case 1: case 2: counter = &(player->weaponctrs[player->readyweapon][cnum]); break; default: return; } // 08/02/04: // support getting check value from a counter // if checktype is greater than the last immediate operator, // then the comparison value is actually a counter number if(checktype >= CPC_NUMIMMEDIATE) { // turn it into the corresponding immediate operation checktype -= CPC_NUMIMMEDIATE; switch(value) { case 0: case 1: case 2: value = player->weaponctrs[player->readyweapon][value]; break; default: return; // invalid counter number } } switch(checktype) { case CPC_LESS: branch = (*counter < value); break; case CPC_LESSOREQUAL: branch = (*counter <= value); break; case CPC_GREATER: branch = (*counter > value); break; case CPC_GREATEROREQUAL: branch = (*counter >= value); break; case CPC_EQUAL: branch = (*counter == value); break; case CPC_NOTEQUAL: branch = (*counter != value); break; case CPC_BITWISEAND: branch = !!(*counter & value); break; default: break; } if(branch) P_SetPsprite(player, psprnum, statenum); }
// // A_CounterOp // // Sets the value of the indicated counter variable for the thing // using two (possibly the same) counters as operands. // // args[0] : counter operand #1 // args[1] : counter operand #2 // args[2] : counter destination // args[3] : operation to perform // void A_CounterOp(Mobj *mo) { int c_oper1_num, c_oper2_num, c_dest_num, specialop; int *c_oper1, *c_oper2, *c_dest; c_oper1_num = E_ArgAsInt(mo->state->args, 0, 0); c_oper2_num = E_ArgAsInt(mo->state->args, 1, 0); c_dest_num = E_ArgAsInt(mo->state->args, 2, 0); specialop = E_ArgAsKwd(mo->state->args, 3, &cpopkwds, 0); if(c_oper1_num < 0 || c_oper1_num >= NUMMOBJCOUNTERS) return; // invalid c_oper1 = &(mo->counters[c_oper1_num]); if(c_oper2_num < 0 || c_oper2_num >= NUMMOBJCOUNTERS) return; // invalid c_oper2 = &(mo->counters[c_oper2_num]); if(c_dest_num < 0 || c_dest_num >= NUMMOBJCOUNTERS) return; // invalid c_dest = &(mo->counters[c_dest_num]); switch(specialop) { case CPOP_ADD: *c_dest = *c_oper1 + *c_oper2; break; case CPOP_SUB: *c_dest = *c_oper1 - *c_oper2; break; case CPOP_MUL: *c_dest = *c_oper1 * *c_oper2; break; case CPOP_DIV: if(c_oper2) // don't divide by zero *c_dest = *c_oper1 / *c_oper2; break; case CPOP_MOD: if(*c_oper2 > 0) // only allow modulus by positive values *c_dest = *c_oper1 % *c_oper2; break; case CPOP_AND: *c_dest = *c_oper1 & *c_oper2; break; case CPOP_OR: *c_dest = *c_oper1 | *c_oper2; break; case CPOP_XOR: *c_dest = *c_oper1 ^ *c_oper2; break; case CPOP_DAMAGE: // do a HITDICE-style calculation if(*c_oper2 > 0) // the modulus must be positive *c_dest = *c_oper1 * ((P_Random(pr_setcounter) % *c_oper2) + 1); break; case CPOP_SHIFTLEFT: *c_dest = *c_oper1 << *c_oper2; break; case CPOP_SHIFTRIGHT: *c_dest = *c_oper1 >> *c_oper2; break; // unary operations (c_oper2 is unused for these) case CPOP_ABS: *c_dest = abs(*c_oper1); break; case CPOP_NEGATE: *c_dest = -(*c_oper1); break; case CPOP_NOT: *c_dest = !(*c_oper1); break; case CPOP_INVERT: *c_dest = ~(*c_oper1); break; default: break; } }