Useful ACS Scripts

Discuss all aspects related to modding Zandronum here.
Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

Useful ACS Scripts

#1

Post by Ijon Tichy » Mon Jun 04, 2012 8:29 am

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]
Last edited by Ijon Tichy on Mon Jun 04, 2012 11:53 am, edited 1 time in total.

Edward-san
Developer
Posts: 382
Joined: Fri May 25, 2012 8:14 pm

RE: Useful ACS Scripts

#2

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

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); }

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#3

Post by Ijon Tichy » Mon Jun 04, 2012 11:54 am

edit'd

Synert
Forum Regular
Posts: 228
Joined: Mon Jun 04, 2012 12:54 pm
Contact:

RE: Useful ACS Scripts

#4

Post by Synert » Mon Jun 04, 2012 1:30 pm


Qent
Retired Staff / Community Team Member
Posts: 1424
Joined: Tue May 29, 2012 7:56 pm
Contact:

RE: Useful ACS Scripts

#5

Post by Qent » Mon Jun 04, 2012 4:51 pm

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:

User avatar
Ivan
Addicted to Zandronum
Posts: 2229
Joined: Mon Jun 04, 2012 5:38 pm
Location: Omnipresent

RE: Useful ACS Scripts

#6

Post by Ivan » Mon Jun 04, 2012 10:34 pm

Pretty useful stuff, thanks for sharing!
=== RAGNAROK DM ON ... uh... dead forever? ===
=== ALWAYS BET ON ... uh... dead forever? ===
=== Who wanta sum wang? ===
=== Death and Decay - A new Monster/Weapon replacer ===

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#7

Post by Ijon Tichy » Fri Jun 22, 2012 1:37 pm

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]

User avatar
ibm5155
Addicted to Zandronum
Posts: 1641
Joined: Tue Jun 05, 2012 9:32 pm
Location: Somewhere, over the rainbow

RE: Useful ACS Scripts

#8

Post by ibm5155 » Sun Jun 24, 2012 7:54 pm

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)
Last edited by ibm5155 on Sun Jun 24, 2012 7:58 pm, edited 1 time in total.

Flaminglacier
 
Posts: 65
Joined: Thu Jun 21, 2012 9:28 pm

RE: Useful ACS Scripts

#9

Post by Flaminglacier » Tue Jun 26, 2012 4:23 am

Could somebody post the invasion script? And the script to make something happen after a wave?
Image

User avatar
Torvald
Forum Regular
Posts: 488
Joined: Tue Jun 26, 2012 3:14 am
Location: Nothern Hemisphere

RE: Useful ACS Scripts

#10

Post by Torvald » Tue Jun 26, 2012 2:58 pm

Gracias for the thread. Very helpful :)

Watermelon
Zandrone
Posts: 1244
Joined: Thu Jun 28, 2012 9:07 pm
Location: Rwanda

RE: Useful ACS Scripts

#11

Post by Watermelon » Fri Jun 29, 2012 5:14 pm

SOMEONE STICKY THIS

Synert
Forum Regular
Posts: 228
Joined: Mon Jun 04, 2012 12:54 pm
Contact:

RE: Useful ACS Scripts

#12

Post by Synert » Fri Jun 29, 2012 6:50 pm

Flaminglacier wrote: Could somebody post the invasion script? And the script to make something happen after a wave?
GetInvasionState and GetInvasionWave.

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#13

Post by Ijon Tichy » Mon Jul 30, 2012 9:07 am

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
Last edited by Ijon Tichy on Mon Jul 30, 2012 9:08 am, edited 1 time in total.

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#14

Post by Ijon Tichy » Thu Sep 13, 2012 1:26 am

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; }
Last edited by Ijon Tichy on Thu Sep 13, 2012 2:20 am, edited 1 time in total.

User avatar
WhoDaMan
 
Posts: 35
Joined: Thu Jun 07, 2012 4:19 pm
Location: Denton, Texas

RE: Useful ACS Scripts

#15

Post by WhoDaMan » Sat Sep 22, 2012 7:34 pm

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?

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#16

Post by Ijon Tichy » Sat Sep 22, 2012 7:56 pm

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

User avatar
WhoDaMan
 
Posts: 35
Joined: Thu Jun 07, 2012 4:19 pm
Location: Denton, Texas

RE: Useful ACS Scripts

#17

Post by WhoDaMan » Sat Sep 22, 2012 9:54 pm

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?

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#18

Post by Ijon Tichy » Sun Sep 23, 2012 12:52 am

you mean like this?

Code: Select all

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

User avatar
WhoDaMan
 
Posts: 35
Joined: Thu Jun 07, 2012 4:19 pm
Location: Denton, Texas

RE: Useful ACS Scripts

#19

Post by WhoDaMan » Sun Sep 23, 2012 1:38 am

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?

Ijon Tichy
Frequent Poster Miles card holder
Posts: 901
Joined: Mon Jun 04, 2012 5:07 am

RE: Useful ACS Scripts

#20

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

Code: Select all

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

Post Reply