Page 1 of 2

Useful ACS Scripts

Posted: Mon Jun 04, 2012 8:29 am
by Ijon Tichy
Since we're all lazy bums and don't want to do things over again, I think it'd be a good idea to have a thread of useful ACS functions/scripts. Because I'm not a prick, FUNCTIONS LOL.

Most of these are small functions, but they really do make scripts more readable when you use them. And you only have to implement it once - what more do you want?

abs, mod, pow(Float):[spoiler]

Code: Select all

function int abs(int x)
{
    if (x < 0) { return -x; }
    return x;
}

function int mod(int x, int y)
{
    int ret = x - ((x / y) * y);
    if (ret < 0) { ret += y; }
    return ret;
}

function int pow(int x, int y)
{
    int n = 1;
    while (y-- > 0) { n *= x; }
    return n;
}

function int powFloat(int x, int y)
{
    int n = 1.0;
    while (y-- > 0) { n = FixedMul(n, x); }
    return n;
}
[/spoiler]

min, max, middle:[spoiler]

Code: Select all

function int min(int x, int y)
{
    if (x < y) { return x; }
    return y;
}

function int max (int x, int y)
{
    if (x > y) { return x; }
    return y;
}

function int middle(int x, int y, int z)
{
    if ((x < z) && (y < z)) { return max(x, y); }
    return max(min(x, y), z);
}
[/spoiler]

Check if key is up, down, or pressed:[spoiler]

Code: Select all

function int keyUp(int key)
{
    int buttons = GetPlayerInput(-1, INPUT_BUTTONS);

    if (~buttons & key) { return 1; }
    return 0;
}

function int keyDown(int key)
{
    int buttons = GetPlayerInput(-1, INPUT_BUTTONS);

    if (buttons & key) { return 1; }
    return 0;
}

function int keyPressed(int key)
{
    int buttons     = GetPlayerInput(-1, INPUT_BUTTONS);
    int oldbuttons  = GetPlayerInput(-1, INPUT_OLDBUTTONS);
    int newbuttons  = (buttons ^ oldbuttons) & buttons;

    if (newbuttons & key) { return 1; }
    return 0;
}
[/spoiler]


This was originally one function in Python, adjust. It worked like this:

Code: Select all

>>> adjust(4, 7, 5)
(4, 7)
>>> adjust(4, 7, 12)
(9, 12)
>>> adjust (4, 7, 2)
(2, 5)
However, since ACS doesn't support returning multiple arguments, nor does it support structs, what we get is me splitting this into two functions. Yeah, not a very good compromise, but what else could I choose?

Range adjusters:[spoiler]

Code: Select all

function int adjustBottom(int tmin, int tmax, int i)
{
    if (i < tmin) { tmin = i; }
    if (i > tmax) { tmin += (i - tmax); }

    return tmin;
}

function int adjustTop(int tmin, int tmax, int i)
{
    if (i < tmin) { tmax -= (tmin - i); }
    if (i > tmax) { tmax = i; }

    return tmax;
}
[/spoiler]

Quadratic formula crap:[spoiler]

Code: Select all

function int sqrt(int number)
{
    if (number == 1.0) { return 1.0;  }
    if (number <= 0) { return 0; }
    int val = 150.0;
    for (int i=0; i<15; i++) { val = (val + FixedDiv(number, val)) >> 1; }

    return val;
}

function int quadPos(int a, int b, int c)
{
    int s1 = sqrt(FixedMul(b, b)-(4*FixedMul(a, c)));
    int s2 = (2 * a);
    int b1 = FixedDiv(-b + s1, s2);

    return b1;
}

function int quadNeg(int a, int b, int c)
{
    int s1 = sqrt(FixedMul(b, b)-(4*FixedMul(a, c)));
    int s2 = (2 * a);
    int b1 = FixedDiv(-b - s1, s2);

    return b1;
}

function int quad(int a, int b, int c, int y)
{
    return FixedMul(a, FixedMul(y, y)) + FixedMul(b, y) + y;
}

function int quadHigh(int a, int b, int c, int x)
{
    return quadPos(a, b, c-x);
}

function int quadLow(int a, int b, int c, int x)
{
    return quadNeg(a, b, c-x);
}
[/spoiler]

itof, ftoi:[spoiler]

Code: Select all

function int itof(int x) { return x << 16; }
function int ftoi(int x) { return x >> 16; }
[/spoiler]

AddAmmoCapacity:[spoiler]

Code: Select all

function void AddAmmoCapacity(int type, int add)
{
    SetAmmoCapacity(type, GetAmmoCapacity(type) + add);
}
[/spoiler]


These functions used to have a disclaimer saying they only worked with StrParam, but as you can probably guess, that's no longer an issue, eh?

String padding, slicing, etc.[spoiler]

Code: Select all

function int inRange(int low, int high, int x)
{
    return ((x >= low) && (x < high));
}

function int padStringR(int baseStr, int padChar, int len)
{
    int baseStrLen = StrLen(baseStr);
    int pad = "";
    int padLen; int i;

    if (baseStrLen >= len)
    {
        return baseStr;
    }
    
    padChar = GetChar(padChar, 0);
    padLen = len - baseStrLen;

    for (i = 0; i < padLen; i++)
    {
        pad = StrParam(s:pad, c:padChar);
    }

    return StrParam(s:baseStr, s:pad);
}

function int padStringL(int baseStr, int padChar, int len)
{
    int baseStrLen = StrLen(baseStr);
    int pad = "";
    int padLen; int i;

    if (baseStrLen >= len)
    {
        return baseStr;
    }
    
    padChar = GetChar(padChar, 0);
    padLen = len - baseStrLen;

    for (i = 0; i < padLen; i++)
    {
        pad = StrParam(s:pad, c:padChar);
    }

    return StrParam(s:pad, s:baseStr);
}

function int changeString(int string, int repl, int where)
{
    int i; int j; int k;
    int ret = "";
    int len = StrLen(string);
    int rLen = StrLen(repl);

    if ((where + rLen < 0) || (where >= len))
    {
        return string;
    }
    
    for (i = 0; i < len; i++)
    {
        if (inRange(where, where+rLen, i))
        {
            ret = StrParam(s:ret, c:GetChar(repl, i-where));
        }
        else
        {
            ret = StrParam(s:ret, c:GetChar(string, i));
        }
    }

    return ret;
}

function int sliceString(int string, int start, int end)
{
    int len = StrLen(string);
    int ret = "";
    int i;

    if (start < 0)
    {
        start = len + start;
    }

    if (end <= 0)
    {
        end = len + end;
    }

    start = max(0, start);
    end   = min(end, len-1);
    
    for (i = start; i < end; i++)
    {
        ret = StrParam(s:ret, c:GetChar(string, i));
    }

    return ret;
}
[/spoiler]

RE: Useful ACS Scripts

Posted: Mon Jun 04, 2012 11:23 am
by Edward-san

Code: Select all

if ((x < z) && (y < z)) { return min(max(x, y), z); }
if x and y are both less than z, the external min usage can be simplified:

Code: Select all

if ((x < z) && (y < z)) { return max(x, y); }

RE: Useful ACS Scripts

Posted: Mon Jun 04, 2012 11:54 am
by Ijon Tichy
edit'd

RE: Useful ACS Scripts

Posted: Mon Jun 04, 2012 1:30 pm
by Synert

RE: Useful ACS Scripts

Posted: Mon Jun 04, 2012 4:51 pm
by Qent
Ijon Tichy wrote: This was originally one function in Python, adjust. It worked like this:

Code: Select all

>>> adjust(4, 7, 5)
(4, 7)
>>> adjust(4, 7, 12)
(9, 12)
>>> adjust (4, 7, 2)
(2, 5)
However, since ACS doesn't support returning multiple arguments, nor does it support structs, what we get is me splitting this into two functions. Yeah, not a very good compromise, but what else could I choose?
Did you consider returning two 16-bit numbers? :razz:

RE: Useful ACS Scripts

Posted: Mon Jun 04, 2012 10:34 pm
by Ivan
Pretty useful stuff, thanks for sharing!

RE: Useful ACS Scripts

Posted: Fri Jun 22, 2012 1:37 pm
by Ijon Tichy
FRED BUMP

In case anyone wants it, here's what I have of commonFuncs.h. You'll almost definitely find something useful in it.

unusedTID:
[spoiler]

Code: Select all

function int unusedTID(int start, int end)
{
    int ret = start - 1;
    int tidNum;

    if (start > end)
    {
        return -127;
    }
    
    while (ret++ != end)
    {
        if (ThingCount(0, ret) == 0)
        {
            return ret;
        }
    }
    
    return -1;
}
[/spoiler]


giveHealth, giveHealthFactor, and getMaxHealth: (better than HealThing)
[spoiler]

Code: Select all

function int getMaxHealth(void)
{
    int maxHP = GetActorProperty(0, APROP_SpawnHealth);

    if ((maxHP == 0) && (PlayerNumber() != -1))
    {
        maxHP = 100;
    }

    return maxHP;
}

function void giveHealth(int amount)
{
    giveHealthFactor(amount, 1.0);
}

function void giveHealthFactor(int amount, int maxFactor)
{
    int maxHP = ftoi(getMaxHealth() * maxFactor);
    int newHP;

    int curHP = GetActorProperty(0, APROP_Health);

    if (maxFactor == 0.0) { newHP = max(curHP, curHP+amount); }
    else { newHP = middle(curHP, curHP+amount, maxHP); }

    SetActorProperty(0, APROP_Health, newHP);
}
[/spoiler]


isFreeForAll and isTeamGame:
[spoiler]

Code: Select all

function int isFreeForAll(void)
{
    if (GetCVar("terminator") || GetCVar("duel"))
    {
        return 1;
    }

    int check1 = GetCVar("deathmatch") || GetCVar("possession") || GetCVar("lastmanstanding");
    int check2 = check1 && !GetCVar("teamplay");

    return check2;
}

function int isTeamGame(void)
{
    int ret = (GetCVar("teamplay") || GetCVar("teamgame"));
    return ret;
}
[/spoiler]


spawnDistance:
[spoiler]

Code: Select all

function int spawnDistance(int item, int dist, int tid)
{
    int myX, myY, myZ, myAng, myPitch, spawnX, spawnY, spawnZ;

    myX = GetActorX(0); myY = GetActorY(0); myZ = GetActorZ(0);
    myAng = GetActorAngle(0); myPitch = GetActorPitch(0);

    spawnX = FixedMul(cos(myAng) * dist, cos(myPitch));
    spawnX += myX;
    spawnY = FixedMul(sin(myAng) * dist, cos(myPitch));
    spawnY += myY;
    spawnZ = myZ + (-sin(myPitch) * dist);

    return Spawn(item, spawnX, spawnY, spawnZ, tid, myAng >> 8);
}
[/spoiler]


GiveAmmo and GiveActorAmmo: (corrects for sv_doubleammo)
[spoiler]

Code: Select all

function void GiveAmmo(int type, int amount)
{
    if (GetCVar("sv_doubleammo"))
    {
        int m = GetAmmoCapacity(type);
        int expected = min(m, CheckInventory(type) + amount);

        GiveInventory(type, amount);
        TakeInventory(type, CheckInventory(type) - expected);
    }
    else
    {  
        GiveInventory(type, amount);
    }
}

function void GiveActorAmmo(int tid, int type, int amount)
{
    if (GetCVar("sv_doubleammo"))
    {
        int m = GetAmmoCapacity(type);
        int expected = min(m, CheckActorInventory(tid, type) + amount);

        GiveActorInventory(tid, type, amount);
        TakeActorInventory(tid, type, CheckActorInventory(tid, type) - expected);
    }
    else
    {  
        GiveActorInventory(tid, type, amount);
    }
}
[/spoiler]


cond: (think "foo = x ? y : z")
[spoiler]

Code: Select all

function int cond(int test, int trueRet, int falseRet)
{
    if (test) { return trueRet; }
    return falseRet;
}
[/spoiler]

RE: Useful ACS Scripts

Posted: Sun Jun 24, 2012 7:54 pm
by ibm5155
To return multiple results it´s simple.

Create two or more multiple global values like value1 and Value2

On the function you just return on the end 0 or something like that, the others values that you want to return you put on the global values
EX:
[spoiler]int X,Y;

script 1 open
{
func(2,5);
}
function int func(int a, int b)
{
X=a*a;
Y=b+X;
return 0;
}[/spoiler]

EDIT: i tried to convert char to string but i didn´t get how to do it (i was going to put a char into a string, but that operation that i saw is not supported in the actual zdoom, so transform char to string would help for now)

RE: Useful ACS Scripts

Posted: Tue Jun 26, 2012 4:23 am
by Flaminglacier
Could somebody post the invasion script? And the script to make something happen after a wave?

RE: Useful ACS Scripts

Posted: Tue Jun 26, 2012 2:58 pm
by Torvald
Gracias for the thread. Very helpful :)

RE: Useful ACS Scripts

Posted: Fri Jun 29, 2012 5:14 pm
by Watermelon
SOMEONE STICKY THIS

RE: Useful ACS Scripts

Posted: Fri Jun 29, 2012 6:50 pm
by Synert
Flaminglacier wrote: Could somebody post the invasion script? And the script to make something happen after a wave?
GetInvasionState and GetInvasionWave.

RE: Useful ACS Scripts

Posted: Mon Jul 30, 2012 9:07 am
by Ijon Tichy
String formatting script, a la obituaries. The codes:
  • %o - name of killed person
  • %k - name of killer
  • %g and %G - gender of killed and killer, subject (he, she, it)
  • %h and %H - gender of killed and killer, predicate (him, her, it)
  • %p and %P - gender of killed and killer, possessive (his, hers, its)
[spoiler]

Code: Select all

script SPREE_FORMATSTR (int which, int killerPln, int killedPln)
{
    int msgString = "";
    int preString = spreeMessages[which];
    int preLen =    StrLen(preString);
    int preChar, preNChar, i;

    int killerGender = GetPlayerInfo(killerPln, PLAYERINFO_GENDER);
    int killedGender = GetPlayerInfo(killedPln, PLAYERINFO_GENDER);

    for (i = 0; i < preLen; i++)
    {
        preChar = GetChar(preString, i);
        preNChar = GetChar(preString, min(i+1, preLen-1));
        
        if (preChar == '\\')
        {
            i++;

            switch (preNChar)
            {
              case 'c':
                msgString = StrParam(s:msgString, c:28);
                break;

              default:
                msgString = StrParam(s:msgString, c:preChar, c:preNChar);
                break;
            }
        }
        else if (preChar == '%')
        {
            i++;
            switch (preNChar)
            {
              case 'k':
                msgString = StrParam(s:msgString, n:killerPln+1, c:28, s:"-");
                break;

              case 'o':
                msgString = StrParam(s:msgString, n:killedPln+1, c:28, s:"-");
                break;

              case 'g':
                msgString = StrParam(s:msgString, s:genders_g[killedGender]);
                break;

              case 'h':
                msgString = StrParam(s:msgString, s:genders_h[killedGender]);
                break;

              case 'p':
                msgString = StrParam(s:msgString, s:genders_p[killedGender]);
                break;

              case 'G':
                msgString = StrParam(s:msgString, s:genders_g[killerGender]);
                break;

              case 'H':
                msgString = StrParam(s:msgString, s:genders_h[killerGender]);
                break;

              case 'P':
                msgString = StrParam(s:msgString, s:genders_p[killerGender]);
                break;

              case '%':
                msgString = StrParam(s:msgString, s:"%");
                break;

              default:
                msgString = StrParam(s:msgString, c:preChar, c:preNChar);
                break;
            }
        }
        else
        {
            msgString = StrParam(s:msgString, c:preChar);
        }
    }

    SetResultValue(msgString);
}
[/spoiler]

edit: obv you should change SPREE_FORMATSTR to a script number

RE: Useful ACS Scripts

Posted: Thu Sep 13, 2012 1:26 am
by Ijon Tichy
Okay so I'll just dump the contents of my commonFuncs.h up to this point, and split it up in an edit

Also on Pastebin.
[spoiler]

Code: Select all

// A bunch of functions that I've built up
// They come in handy :>

function int abs(int x)
{
    if (x < 0) { return -x; }
    return x;
}

function int sign(int x)
{
    if (x < 0) { return -1; }
    return 1;
}

function int randSign(void)
{
    return (2*random(0,1))-1;
}

function int mod(int x, int y)
{
    int ret = x - ((x / y) * y);
    if (ret < 0) { ret = y + ret; }
    return ret;
}

function int pow(int x, int y)
{
    int n = 1;
    while (y-- > 0) { n *= x; }
    return n;
}

function int powFloat(int x, int y)
{
    int n = 1.0;
    while (y-- > 0) { n = FixedMul(n, x); }
    return n;
}

function int min(int x, int y)
{
    if (x < y) { return x; }
    return y;
}

function int max (int x, int y)
{
    if (x > y) { return x; }
    return y;
}

function int middle(int x, int y, int z)
{
    if ((x < z) && (y < z)) { return max(x, y); }
    return max(min(x, y), z);
}

function int percFloat(int intg, int frac)
{
    return (intg << 16) + ((frac << 16) / 100);
}

function int percFloat2(int intg, int frac1, int frac2)
{
    return itof(intg) + (itof(frac1) / 100) + (itof(frac2) / 10000);
}

function int keyUp(int key)
{
    int buttons = GetPlayerInput(-1, INPUT_BUTTONS);

    if ((~buttons & key) == key) { return 1; }
    return 0;
}

function int keyDown(int key)
{
    int buttons = GetPlayerInput(-1, INPUT_BUTTONS);

    if ((buttons & key) == key) { return 1; }
    return 0;
}

function int keyPressed(int key)
{
    int buttons     = GetPlayerInput(-1, INPUT_BUTTONS);
    int oldbuttons  = GetPlayerInput(-1, INPUT_OLDBUTTONS);
    int newbuttons  = (buttons ^ oldbuttons) & buttons;

    if ((newbuttons & key) == key) { return 1; }
    return 0;
}

function int adjustBottom(int tmin, int tmax, int i)
{
    if (tmin > tmax)
    {
        tmax ^= tmin; tmin ^= tmax; tmax ^= tmin;  // XOR swap
    }

    if (i < tmin) { tmin = i; }
    if (i > tmax) { tmin += (i - tmax); }

    return tmin;
}

function int adjustTop(int tmin, int tmax, int i)
{
    if (tmin > tmax)
    {
        tmax ^= tmin; tmin ^= tmax; tmax ^= tmin;
    }

    if (i < tmin) { tmax -= (tmin - i); }
    if (i > tmax) { tmax = i; }

    return tmax;
}

function int adjustShort(int tmin, int tmax, int i)
{
    if (tmin > tmax)
    {
        tmax ^= tmin; tmin ^= tmax; tmax ^= tmin;
    }

    if (i < tmin)
    {
        tmax -= (tmin - i);
        tmin = i;
    }
    if (i > tmax)
    {
        tmin += (i - tmax);
        tmax = i;
    }
    
    return packShorts(tmin, tmax);
}


// Taken from http://zdoom.org/wiki/sqrt

function int sqrt_i(int number)
{
	if (number <= 3) { return number > 0; }

	int oldAns = number >> 1,                     // initial guess
	    newAns = (oldAns + number / oldAns) >> 1; // first iteration

	// main iterative method
	while (newAns < oldAns)
	{
		oldAns = newAns;
		newAns = (oldAns + number / oldAns) >> 1;
	}

	return oldAns;
}

function int sqrt(int number)
{
    if (number == 1.0) { return 1.0; }
    if (number <= 0) { return 0; }
    int val = 150.0;
    for (int i=0; i<15; i++) { val = (val + FixedDiv(number, val)) >> 1; }

    return val;
}

function int magnitudeTwo(int x, int y)
{
    return sqrt_i(x*x + y*y);
}

function int magnitudeTwo_f(int x, int y)
{
    return sqrt(FixedMul(x, x) + FixedMul(y, y));
}

function int magnitudeThree(int x, int y, int z)
{
    return sqrt_i(x*x + y*y + z*z);
}

function int magnitudeThree_f(int x, int y, int z)
{
    return sqrt(FixedMul(x, x) + FixedMul(y, y) + FixedMul(z, z));
}


function int quadPos(int a, int b, int c)
{
    int s1 = sqrt(FixedMul(b, b)-(4*FixedMul(a, c)));
    int s2 = (2 * a);
    int b1 = FixedDiv(-b + s1, s2);

    return b1;
}

function int quadNeg(int a, int b, int c)
{
    int s1 = sqrt(FixedMul(b, b)-(4*FixedMul(a, c)));
    int s2 = (2 * a);
    int b1 = FixedDiv(-b - s1, s2);

    return b1;
}

function int quad(int a, int b, int c, int y)
{
    return FixedMul(a, FixedMul(y, y)) + FixedMul(b, y) + c + y;
}

function int quadHigh(int a, int b, int c, int x)
{
    return quadPos(a, b, c-x);
}

function int quadLow(int a, int b, int c, int x)
{
    return quadNeg(a, b, c-x);
}

function int inRange(int low, int high, int x)
{
    return ((x >= low) && (x < high));
}

function int itof(int x) { return x << 16; }
function int ftoi(int x) { return x >> 16; }

function void AddAmmoCapacity(int type, int add)
{
    SetAmmoCapacity(type, GetAmmoCapacity(type) + add);
}

function int packShorts(int left, int right)
{
    return ((left & 0xFFFF) << 16) + (right & 0xFFFF);
}

function int leftShort(int packed) { return packed >> 16; }
function int rightShort(int packed) { return (packed << 16) >> 16; }


// This stuff only works with StrParam

function int cleanString(int string)
{
    int ret = "";
    int strSize = StrLen(string);

    int c, i, ignoreNext;
    
    for (i = 0; i < strSize; i++)
    {
        c = GetChar(string, i);

        if ( ( ((c > 8) && (c < 14)) || ((c > 31) && (c < 127)) || ((c > 160) && (c < 173)) ) && !ignoreNext)
        {
            ret = StrParam(s:ret, c:c);
        }
        else if (c == 28 && !ignoreNext)
        {
            ignoreNext = 1;
        }
        else
        {
            ignoreNext = 0;
        }
    }

    return ret;
}

function int padStringR(int baseStr, int padChar, int len)
{
    int baseStrLen = StrLen(baseStr);
    int pad = "";
    int padLen; int i;

    if (baseStrLen >= len)
    {
        return baseStr;
    }
    
    padChar = GetChar(padChar, 0);
    padLen = len - baseStrLen;

    for (i = 0; i < padLen; i++)
    {
        pad = StrParam(s:pad, c:padChar);
    }

    return StrParam(s:baseStr, s:pad);
}

function int padStringL(int baseStr, int padChar, int len)
{
    int baseStrLen = StrLen(baseStr);
    int pad = "";
    int padLen; int i;

    if (baseStrLen >= len)
    {
        return baseStr;
    }
    
    padChar = GetChar(padChar, 0);
    padLen = len - baseStrLen;

    for (i = 0; i < padLen; i++)
    {
        pad = StrParam(s:pad, c:padChar);
    }

    return StrParam(s:pad, s:baseStr);
}

function int changeString(int string, int repl, int where)
{
    int i; int j; int k;
    int ret = "";
    int len = StrLen(string);
    int rLen = StrLen(repl);

    if ((where + rLen < 0) || (where >= len))
    {
        return string;
    }
    
    for (i = 0; i < len; i++)
    {
        if (inRange(where, where+rLen, i))
        {
            ret = StrParam(s:ret, c:GetChar(repl, i-where));
        }
        else
        {
            ret = StrParam(s:ret, c:GetChar(string, i));
        }
    }

    return ret;
}

function int sliceString(int string, int start, int end)
{
    int len = StrLen(string);
    int ret = "";
    int i;

    if (start < 0)
    {
        start = len + start;
    }

    if (end <= 0)
    {
        end = len + end;
    }

    start = max(0, start);
    end   = min(end, len-1);
    
    for (i = start; i < end; i++)
    {
        ret = StrParam(s:ret, c:GetChar(string, i));
    }

    return ret;
}

// End StrParam

function int unusedTID(int start, int end)
{
    int ret = start - 1;
    int tidNum;

    if (start > end) { start ^= end; end ^= start; start ^= end; }  // good ol' XOR swap
    
    while (ret++ != end)
    {
        if (ThingCount(0, ret) == 0)
        {
            return ret;
        }
    }
    
    return -1;
}

function int getMaxHealth(void)
{
    int maxHP = GetActorProperty(0, APROP_SpawnHealth);

    if ((maxHP == 0) && (PlayerNumber() != -1))
    {
        maxHP = 100;
    }

    return maxHP;
}

function void giveHealth(int amount)
{
    giveHealthFactor(amount, 1.0);
}

function void giveHealthFactor(int amount, int maxFactor)
{
    int maxHP = ftoi(getMaxHealth() * maxFactor);
    int newHP;

    int curHP = GetActorProperty(0, APROP_Health);

    if (maxFactor == 0.0) { newHP = max(curHP, curHP+amount); }
    else { newHP = middle(curHP, curHP+amount, maxHP); }

    SetActorProperty(0, APROP_Health, newHP);
}

function int isDead(int tid)
{
    return GetActorProperty(tid, APROP_Health) <= 0;
}

function int isFreeForAll(void)
{
    if (GetCVar("terminator") || GetCVar("duel"))
    {
        return 1;
    }

    int check1 = GetCVar("deathmatch") || GetCVar("possession") || GetCVar("lastmanstanding");
    int check2 = check1 && !GetCVar("teamplay");

    return check2;
}

function int isTeamGame(void)
{
    int ret = (GetCVar("teamplay") || GetCVar("teamgame"));
    return ret;
}

function int spawnDistance(int item, int dist, int tid)
{
    int myX, myY, myZ, myAng, myPitch, spawnX, spawnY, spawnZ;

    myX = GetActorX(0); myY = GetActorY(0); myZ = GetActorZ(0);
    myAng = GetActorAngle(0); myPitch = GetActorPitch(0);

    spawnX = FixedMul(cos(myAng) * dist, cos(myPitch));
    spawnX += myX;
    spawnY = FixedMul(sin(myAng) * dist, cos(myPitch));
    spawnY += myY;
    spawnZ = myZ + (-sin(myPitch) * dist);

    return Spawn(item, spawnX, spawnY, spawnZ, tid, myAng >> 8);
}

function void SetInventory(int item, int amount)
{
    int count = CheckInventory(item);

    if (count == amount) { return; }
    
    if (count > amount)
    {
        TakeInventory(item, count - amount);
        return;
    }

    GiveAmmo(item, amount - count);
    return;
}
function void ToggleInventory(int inv)
{
    if (CheckInventory(inv))
    {
        TakeInventory(inv, 0x7FFFFFFF);
    }
    else
    {
        GiveInventory(inv, 1);
    }
}

function void GiveAmmo(int type, int amount)
{
    if (GetCVar("sv_doubleammo"))
    {
        int m = GetAmmoCapacity(type);
        int expected = min(m, CheckInventory(type) + amount);

        GiveInventory(type, amount);
        TakeInventory(type, CheckInventory(type) - expected);
    }
    else
    {  
        GiveInventory(type, amount);
    }
}

function void GiveActorAmmo(int tid, int type, int amount)
{
    if (GetCVar("sv_doubleammo"))
    {
        int m = GetAmmoCapacity(type);
        int expected = min(m, CheckActorInventory(tid, type) + amount);

        GiveActorInventory(tid, type, amount);
        TakeActorInventory(tid, type, CheckActorInventory(tid, type) - expected);
    }
    else
    {  
        GiveActorInventory(tid, type, amount);
    }
}

function int cond(int test, int trueRet, int falseRet)
{
    if (test) { return trueRet; }
    return falseRet;
}

function int condTrue(int test, int trueRet)
{
    if (test) { return trueRet; }
    return test;
}

function int condFalse(int test, int falseRet)
{
    if (test) { return test; }
    return falseRet;
}

function void saveCVar(int cvar, int val)
{
    ConsoleCommand(StrParam(s:"set ", s:cvar, s:" ", d:val));
    ConsoleCommand(StrParam(s:"archivecvar ", s:cvar));
}

function int defaultCVar(int cvar, int defaultVal)
{
    int ret = GetCVar(cvar);
    if (ret == 0) { saveCVar(cvar, defaultVal); return defaultVal; }

    return ret;
}


function int onGround(int tid)
{
    return (GetActorZ(tid) - GetActorFloorZ(tid)) == 0;
}

function int ThingCounts(int start, int end)
{
    int i, ret = 0;

    if (start > end) { start ^= end; end ^= start; start ^= end; }
    for (i = start; i < end; i++) { ret += ThingCount(0, i); }

    return ret;
}

function int PlaceOnFloor(int tid)
{
    if (ThingCount(0, tid) != 1) { return 1; }
    
    SetActorPosition(tid, GetActorX(tid), GetActorY(tid), GetActorFloorZ(tid), 0);
    return 0;
}

#define DIR_E  1
#define DIR_NE 2
#define DIR_N  3
#define DIR_NW 4
#define DIR_W  5
#define DIR_SW 6
#define DIR_S  7
#define DIR_SE 8

function int getDirection(void)
{
    int sideMove = keyDown(BT_MOVERIGHT) - keyDown(BT_MOVELEFT);
    int forwMove = keyDown(BT_FORWARD) - keyDown(BT_BACK);

    if (sideMove || forwMove)
    {
        switch (sideMove)
        {
          case -1: 
            switch (forwMove)
            {
                case -1: return DIR_SW;
                case  0: return DIR_W;
                case  1: return DIR_NW;
            }
            break;

          case 0: 
            switch (forwMove)
            {
                case -1: return DIR_S;
                case  1: return DIR_N;
            }
            break;

          case 1: 
            switch (forwMove)
            {
                case -1: return DIR_SE;
                case  0: return DIR_E;
                case  1: return DIR_NE;
            }
            break;
        }
    }

    return 0;
}

function int isInvulnerable(void)
{
    int check1 = GetActorProperty(0, APROP_Invulnerable);
    int check2 = CheckInventory("PowerInvulnerable");

    return check1 || check2;
}

function void saveStringCVar(int string, int cvarname)
{
    int slen = StrLen(string);
    int i, c, cvarname2;

    for (i = 0; i < slen; i++)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        SaveCVar(cvarname2, GetChar(string, i));
    }

    while (1)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        c = GetCVar(cvarname2);

        if (c == 0) { break; }

        ConsoleCommand(StrParam(s:"unset ", s:cvarname2));
        i += 1;
    }
}

function int loadStringCVar(int cvarname)
{
    int ret = "";
    int i = 0, c, cvarname2;

    while (1)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        c = GetCVar(cvarname2);

        if (c == 0) { break; }

        ret = StrParam(s:ret, c:c);
        i += 1;
    }

    return ret;
}
[/spoiler]


Saving CVars, and automatically setting a CVar if it's 0

Code: Select all

function void saveCVar(int cvar, int val)
{
    ConsoleCommand(StrParam(s:"set ", s:cvar, s:" ", d:val));
    ConsoleCommand(StrParam(s:"archivecvar ", s:cvar));
}

function int defaultCVar(int cvar, int defaultVal)
{
    int ret = GetCVar(cvar);
    if (ret == 0) { saveCVar(cvar, defaultVal); return defaultVal; }

    return ret;
}
Floor-related functions:

Code: Select all

function int onGround(int tid)
{
    return (GetActorZ(tid) - GetActorFloorZ(tid)) == 0;
}

function int PlaceOnFloor(int tid)
{
    if (ThingCount(0, tid) != 1) { return 1; }
    
    SetActorPosition(tid, GetActorX(tid), GetActorY(tid), GetActorFloorZ(tid), 0);
    return 0;
}
Count all the things in a TID range:

Code: Select all

function int ThingCounts(int start, int end)
{
    int i, ret = 0;

    if (start > end) { start ^= end; end ^= start; start ^= end; }
    for (i = start; i < end; i++) { ret += ThingCount(0, i); }

    return ret;
}
Get the direction a player is moving (requires keyDown):

Code: Select all

#define DIR_E  1
#define DIR_NE 2
#define DIR_N  3
#define DIR_NW 4
#define DIR_W  5
#define DIR_SW 6
#define DIR_S  7
#define DIR_SE 8

function int getDirection(void)
{
    int sideMove = keyDown(BT_MOVERIGHT) - keyDown(BT_MOVELEFT);
    int forwMove = keyDown(BT_FORWARD) - keyDown(BT_BACK);

    if (sideMove || forwMove)
    {
        switch (sideMove)
        {
          case -1: 
            switch (forwMove)
            {
                case -1: return DIR_SW;
                case  0: return DIR_W;
                case  1: return DIR_NW;
            }
            break;

          case 0: 
            switch (forwMove)
            {
                case -1: return DIR_S;
                case  1: return DIR_N;
            }
            break;

          case 1: 
            switch (forwMove)
            {
                case -1: return DIR_SE;
                case  0: return DIR_E;
                case  1: return DIR_NE;
            }
            break;
        }
    }

    return 0;
}
Checking for invulnerability (might need to add conditions for your specific use):

Code: Select all

function int isInvulnerable(void)
{
    int check1 = GetActorProperty(0, APROP_Invulnerable);
    int check2 = CheckInventory("PowerInvulnerable");

    return check1 || check2;
}
Saving and loading string CVars (no, seriously)

Code: Select all

function void saveStringCVar(int string, int cvarname)
{
    int slen = StrLen(string);
    int i, c, cvarname2;

    for (i = 0; i < slen; i++)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        SaveCVar(cvarname2, GetChar(string, i));
    }

    while (1)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        c = GetCVar(cvarname2);

        if (c == 0) { break; }

        ConsoleCommand(StrParam(s:"unset ", s:cvarname2));
        i += 1;
    }
}

function int loadStringCVar(int cvarname)
{
    int ret = "";
    int i = 0, c, cvarname2;

    while (1)
    {
        cvarname2 = StrParam(s:cvarname, s:"_char", d:i);
        c = GetCVar(cvarname2);

        if (c == 0) { break; }

        ret = StrParam(s:ret, c:c);
        i += 1;
    }

    return ret;
}
Packing and unpacking shorts (never bothered modifying adjustLeft and adjustRight to use this):

Code: Select all

function int packShorts(int left, int right)
{
    return ((left & 0xFFFF) << 16) + (right & 0xFFFF);
}

function int leftShort(int packed) { return packed >> 16; }
function int rightShort(int packed) { return (packed << 16) >> 16; }

RE: Useful ACS Scripts

Posted: Sat Sep 22, 2012 7:34 pm
by WhoDaMan
I have a question about Thingcount in invsion. I'm trying to get a Hudmessege to display how many of a certain group of monsters are left alive using this script

Code: Select all

script 31 OPEN
{
	While(ThingCount(T_NONE, 249) > 11)


	hudmessage (s:"12 of 12 Monsters"; HUDMSG_PLAIN, 6, CR_YELLOW, 0.8,  0.2, 0);

}
Meaning if all 12 monsters with a TiD of 249 in the group were still alive it would show it and so on and so fourth. Problem is that its not working.
First I tried giving all those monsters a Spawn ID of 249. When that didnt work I tried to change there Spawn ID to 249 with this.

Code: Select all

script 28 (void)
{
    Thing_ChangeTID (0, 249);
}
I put ACS_Execute in the monsters spawn state but still no luck. Does anyone know what I am doing wrong?

RE: Useful ACS Scripts

Posted: Sat Sep 22, 2012 7:56 pm
by Ijon Tichy
most likely, the open script is running, checking the amount of monsters with TID (not spawn ID) 249, finding none, and quitting before the monsters ever have their TID set to 249

RE: Useful ACS Scripts

Posted: Sat Sep 22, 2012 9:54 pm
by WhoDaMan
I see, that's what I was afraid of. One other question. Is there a way to have multiple Thingcount functions in one script so I don't have to use 12 different scripts?

RE: Useful ACS Scripts

Posted: Sun Sep 23, 2012 12:52 am
by Ijon Tichy
you mean like this?

Code: Select all

while (ThingCount(0, 248) > 11 ||
       ThingCount(0, 249) > 11 ||
       ThingCount(0, 1001) == 1)
{
    // do things
}

RE: Useful ACS Scripts

Posted: Sun Sep 23, 2012 1:38 am
by WhoDaMan
Well Sort of. I was hopeing for something a little more like this.

Code: Select all

{
    While(ThingCount(T_NONE, 249) > 11)

    hudmessage (s:"12 of 12 Monsters"; HUDMSG_PLAIN, 6, CR_YELLOW, 0.8,  0.2, 0);

    While(ThingCount(T_NONE, 249) > 10)

    hudmessage (s:"11 of 12 Monsters"; HUDMSG_PLAIN, 6, CR_YELLOW, 0.8,  0.2, 0);

   While(ThingCount(T_NONE, 249) > 9)

    hudmessage (s:"10 of 12 Monsters"; HUDMSG_PLAIN, 6, CR_YELLOW, 0.8,  0.2, 0);


}
Is something like that possible in one script?

RE: Useful ACS Scripts

Posted: Sun Sep 23, 2012 3:31 am
by Ijon Tichy

Code: Select all

HudMessage(d:ThingCount(T_NONE, 249), s:" of 12 monsters"; HUDMSG_PLAIN, 6, CR_YELLOW, 0.8, 0.2, 0);