Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
Cacowad

binding a monster to acs

Recommended Posts

hello everybody, a quick question:

i want a monster spawn an item upon it's death using acs, as example i spawn an imp using the Spawnspot command, and i give him a non unique tid of 200, then i call

 SetThingSpecial(200, ACS_ExecuteAlways, 2); 
where 2 is this script i stole and adapted from the wiki :
script 2 (void)
 {
   int n = 2;
     while (n > 0)
     {
       int x = GetActorX(0);
       int y = GetActorY(0);
       int z = GetActorceilingZ(0) - 8.0;
       type = random (0,7);
       if (Spawn(itemlist[type] , x, y, z)){
         n--;
         }

 
       delay(1);
   }
 }

where the array itemlist is a generic ammo list.
where is the problem? it is normally executed after the monster death, but seems that can't exit the while loop, why? i know that the if() is a failsafe condition, so it is unable to summon the item? i need to randomize the coordinates? i am scratching my head for a while now...

another question: when i kill the poor imp, is he or i the activator of the script? if i am the activator, there is no need of such script, i want to be the monster to spawn the item.

Share this post


Link to post

The default height of an actor is 16. You spawn them 8 units below the ceiling, meaning that they are height units inside the ceiling, which makes the spawning fail.

Lower to ceilingz - 24.0 (a bit of margin for safety) and it should work.

Share this post


Link to post

yes now it work, but as i feared the activator is the player, not the imp, thank you anyway, i have to find another way to get the coordinates of the imp on it's death.

Share this post


Link to post

Why don't you use 200 instead of 0 for the various GetActorCoordinate(tid) calls?

Share this post


Link to post

I was fiddling around trying it and came up with:

#include "zcommon.acs"

int whatToSpawn[4] = {"soulsphere", "medikit", "radsuit", "berserk"};

script 1 open
{
    spawn("doomimp", 64.0, 64.0, 0, 200, 192);
    int checkingIfDead = 1;
    while(checkingIfDead)
    {
        //print(d:getactorproperty(200,APROP_health));
        //if(checkactorproperty(200,aprop_health,0))
        if(thingcount(t_none, 200) == 0)
        {
            checkingIfDead = 0;
            int r = random(0,3);
            spawn(whatToSpawn[r], getactorx(200), getactory(200), 300, 192);
        }
        delay(1);
    }
    print(s: "that bitch died lol");
}
first i tried to check the actors health and if it was <= 0, spawn whatever. But checkactorproperty(200,aprop_health,0) apparently can only check if the value is EQUAL to 0, not LESS THAN OR EQUAL to 0 (and apparently when you kill an imp its health can go negative). So I used thingcount instead.
If you want like 10 imps that all spawn something when they die... I dunno, maybe give each a different tid.
I was trying to use acs only. I think you can just right click the thing and give it an action of excecute, which happens when it dies I think.

Share this post


Link to post
gggmork said:

first i tried to check the actors health and if it was <= 0, spawn whatever. But checkactorproperty(200,aprop_health,0) apparently can only check if the value is EQUAL to 0, not LESS THAN OR EQUAL to 0 (and apparently when you kill an imp its health can go negative). So I used thingcount instead.

Use GetActorProperty for that, as function returns the value of the property you're checking on.

Share this post


Link to post
Gez said:

Why don't you use 200 instead of 0 for the various GetActorCoordinate(tid) calls?


becouse i am doing a bit messy thing, actually i am modifing a random monster spawner that i have done some times ago... the purpose is this: i set only mapspots into the map, each spawnspot spawn an another spawnspot that will have an unique tid (still in progress, by now i must do group of mapspots for different arrays of monsters), then each mapspot will spawn a random monster based on the difficulty level (different difficulty will have different chance of spawning different monsters, not implemented yet but easy to do). the monsters are classified into 4 arrays : easy, medium, large, boss; and each array of monsters have it's tier tid, so the item spawned on monster's death will go accordingly to it's tier.

this bring back us to the problem, becouse i can't call directly the monsters's id i have to find a way to be the monster the calling actor of the script, and unfortunatly the enter type script work only on players.

gggmork: actually you gave me an idea... but i don't know if it will be too much resources consuming, and also it will not solve the problem that the item spawned will be spawned at every things tagged with 200, so if you have 3 imps you can check if the count has decreased, but every time one of them die, everyone will spawn an item, and that's no good.

if posting the buggy code in it's entirely will help to make things clearer, just say it, and i will post it.

Share this post


Link to post

Have you fiddled with decorate instead of acs, like look at dropitem:
http://zdoom.org/wiki/Actor_properties#DropItem
and how its used for zombieman:
http://zdoom.org/wiki/ZombieMan
I remember decorate can have user variables:
http://zdoom.org/wiki/User_variable
or something, but forget exactly because I havn't used decorate much.

Not sure what you want to do 100% based on your description. Here's a zdoom map I made some time ago where monsters and items randomly spawned, though I never had monsters spawn items:
http://filesmelt.com/dl/gpRespawnXWE.zip
Forget if I used decorate much.

Share this post


Link to post

uhuh, that sound intriguing, another entry to my strange wads collection... anyway i know how to make it using decorate ,is really easy to do. using decorate you can also make a uber monster spawner without using a single line of acs (oh, well, maybe just spawnspot and a skill level checker if you want to make it perfect, but thats it).

all this headchace is just becouse this code is for a community project map http://www.doomworld.com/vb/wads-mods/62724-so-you-think-you-can-map-monochrome-mapping-project-update-4/] this actually so i want to do not use any form of decorate, maybe it is just stupid to do in acs after all, well seems i need to post some more code.

//variables and arrays

str demonlistE[4] = {"Zombieman","shotgunguy",
"DoomImp","Demon"};
str demonlistS[6] = {"HellKnight","Cacodemon",
"Chaingunguy","Revenant","LostSoul","Spectre"};
str demonlistM[5] = {"PainElemental","Arachnotron","Fatso","BaronOfHell","Archvile"};
str demonlistL[2] = {"Cyberdemon","SpiderMastermind"};
str itemlist[8] = {"cell", "cellpack", "Clip", "clipbox", "rocketammo", "rocketbox", "shell", "shellbox"}; 
//i need to add another item array and modify the existent one.
int spot = 0;
int type = 0;
int emptyspot = 2;
int spot2 = 0;



//actual script--------------------------------------------
 script 3 enter
 {
 spot = thingcount (T_none,2);
 
 spot2 = 1000 + spot;
 emptyspot = 2;
 for (int filled = 1000 ; !(filled > spot2) ; spot2--)
 {
    spawnspot ("MapSpot",emptyspot,spot2,0);
    emptyspot = spot2;
 }

 int wave = 1000 + spot;
 
 for (int waves = 1000 ; !(waves > wave) ; waves++)
    {
    int size = random (1,3);
    if (size == 1 )
        {
        type = random (0,5);
        spawnspot (demonlistS[type],waves,300,0);
        SetThingSpecial(300, ACS_ExecuteAlways, 2);
        }
    else if (size == 2)
        {
         type = random (0,4);
         spawnspot (demonlistM[type],waves,200,0);
         SetThingSpecial(200, ACS_ExecuteAlways, 4);
        }
    else if (size == 3)
        {
        type = random (0,3);
        spawnspot (demonlistE[type],waves,100,0);
        }
    else;
    }

}

//wilderness generator aka script i have used as a base, the arrays are a bit different
//becouse i had used more monsters variety 

script 11 (void)
{
 wave = random (11,22);
 for (int waves = 0 ; !(waves == wave) ; waves++)
 {
 size = random (1,10);
 if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 )
    {
     type = random (0,21);
           spawnspot (demonlistS[type],3,200,0);
           thing_setgoal (200,4,0,0);
           delay (70);
    }
 if (size == 6 || size == 7 || size == 8 || size == 9)
    {
     type = random (0,7);
           spawnspot (demonlistM[type],2,200,0);
           thing_setgoal (200,4,0,0);
           delay (70);
    }
 if (size == 10)
    {
     type = random (0,8);
           spawnspot (demonlistL[type],11,200,0);
           thing_setgoal (200,4,0,0);
           delay (70);
    }
  delay (70);
  }
}

boss monsters (cybra , brain) are treated in a different way, script 4 is a variant of script 2, skill level randomness still to add(but it is not a problem), the real deal is setting the right tid to the various mapspots all at once without needing to regroup them into 4 groups of tid (es: 2-3-4-5), since i am too lazy to set them manually (will check gggmork wad now), also there is the imp problem from before still not solved.

is a bit clearer?...

edit: code updated to make it spawn unique-tid-assigned mapspot, still does not work as intended, it still spawn only one randomic variety of monster. variables declarated at the beginning of the code.

Share this post


Link to post

Hmm, maybe try to write in english the precise thing you want to accomplish because I don't really understand still.
Like is the map supposed to start with things (map spots or whatever) already in the map, or does everything come into existence through acs? What things are supposed to exist and what are they supposed to do?

Your code has weird stuff like:
!(filled > spot2)
when probably
filled < spot2
would be the normal way I assume.

Like you want to spawn a bunch of enemies or something on pre-existing map spots? In waves? All at once? Different types of enemies? Like in a line or a grid, random locations, how far apart, etc? All enemies should drop a random item or something at their death spot?

Share this post


Link to post

ok, at the start of the map there are only mapspots with fixed tag. these mapspots have to spawn another mapspot giving it an unique tid in the process.

monsters have to spawn to a random mapspot, 1 mapspot = 1 monster, all variety of monsters are used and classified using arrays. with the increase of the skill level chosen at start, there should be less probability to spawn a weak monster instead of a big one.

all monsters (except the weaker ones like zombies, imps and pinkyes) should drop an item at their death location. that item is randomly chosen and classified using the tier of the monsters that should drop it (es: cacodemon should drop less ammo/health than a baron of hell).

tanks for your patience, i am not very good when comes to explain things...

Share this post


Link to post

For each mapspot already there at the start, how many more mapspots should it create?
For example, each single mapspot, represented by an "M":

M
could become:
M M M M M
M M M M M
M M M M M
a 5x3 grid of mapspots (or whatever else you prefer). And how far apart, like 64/128/256/etc. Fat masterminds won't warp unless they're 128+ far apart, and even then one of the other warpers might stand on its warping spot, but I could probably repeatedly try to warp until successful.

So a random monster (depending on skill level) is supposed to warp to EVERY mapspot? All at once? Like maybe every 2 minutes or something, another wave of warpers comes in, or just one wave at the beginning? Or do they constantly come to random warps at random times instead of all at the same time?

Share this post


Link to post

just one random warp at the beginning of the map. the monsters warped must not be all of the same class. additional warps does not count.

in my thoughts, each spawnspot should spawn 1 unique-tid-assigned spawnspot. i see what you did here, surely is a more efficient solution than mine, that was based on the assumption that if a warp point is already occupied then another thing can't be spawned on the same spot.

doing this way we can have something like this maybe?:

int positiony [9] = {0,64,-64,128,-128,192,-192,256,-256};
int positionx [9] = {0,64,-64,128,-128,192,-192,256,-256};

script 5 enter 
{
int totalpoints = 81;
int x = GetActorX(2);
int y = GetActorY(2);
int z = GetActorz(2);
int posx = 0;
int posy = 0;


for (int spawned = 0; !(spawned == totalpoints); totalpoints--)
{
    spawn ("mapspot",(x + positionx[posx]),(y + positiony[posy]),(z + 24),(1000 + spot),0);
    spot++;
    if (posx == 8 && posy == 9);  
  
    else if ((posx < 8) && (posy< 9))
            posx++;
        else if (posx == 8 && (posy < 8)) {
                posx = 0;
                posy++;
                }
            else;
}


int wave = 1000 + spot;
 
 for (int waves = 1000 ; !(waves > wave) ; waves++)
    {
    int size = random (1,3);
    if (size == 1 )
        {
        type = random (0,5);
        spawnspot (demonlistS[type],waves,300,0);
        SetThingSpecial(300, ACS_ExecuteAlways, 2);
        }
    else if (size == 2)
        {
         type = random (0,4);
         spawnspot (demonlistM[type],waves,200,0);
         SetThingSpecial(200, ACS_ExecuteAlways, 4);
        }
    else if (size == 3)
        {
        type = random (0,3);
        spawnspot (demonlistE[type],waves,100,0);
        }
    else;
    }
}
all that assuming that there are no z variations. this is supposed to spawn a 9x9 grid of randomic monsters, but this actually only spawn a lone monster, i am missing something? maybe i have missundertood the conversion from fixed points to map units?

Share this post


Link to post

Ok, I figured it out:

make a doom in hexen map. put 3 mapspots in, tagged 1-3 (if have more mapspots, have to change the
#define numberOfInitialMapspots 3
value.
Then this code should work I guess (works for me). Have to fiddle with values in the arrays to do what you want and stuff.

If you run this, does it print "(whichever monster) died" every time someone dies? For me it keeps printing "allmap died" but I think that's just cuz I re-edited an old wad with unintentional lingering cacodemon decorate, which shouldn't be a problem for your wad.

#include "zcommon.acs"

//PUT HOW MANY INITIAL MAPSPOTS THERE ARE
//and give each initial mapspot a ++ numbered tid starting at 1
#define numberOfInitialMapspots 3
//a list of points, each with an [x,y]
int initialPoints[numberOfInitialMapspots][2];
int items[14] = {"Allmap","ArmorBonus","Berserk","BlueArmor","BlurSphere","GreenArmor","HealthBonus",
          "Infrared","InvulnerabilitySphere","Medikit","Megasphere","RadSuit","Soulsphere","Stimpack"};
int monsters[18] = {"arachnotron", "archvile", "baronofhell", "hellknight", "cacodemon", "cyberdemon", 
                    "demon", "spectre", "chaingunguy", "doomimp", "fatso", "lostsoul", "painelemental",
                    "revenant", "shotgunguy", "spidermastermind", "wolfensteinss", "zombieman"};
int SpawnedItemChances[18][14] = {{0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
            //see, the below array is the 14th index of spawnedItemChances (counting starts at 0)
            //which is the shotgun guy (14th of monsters array)
            //I set 2:berserk to 9 and 4:blursphere to 14.
            //this means 9/23 chance for berserk and 14/23 chance for blursphere (23 is 14+9)
            //(corresponding to position in the items[] array)
                                  {0,0,9,0,14,0,0,0,0,0,0,0,0,0},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4},
                                  {0,9,4,0,2,0,0,1,6,0,0,0,0,4}};
//below 5 arays correspond to 5 skills, like 6+4+3+2+9+9+9=42, so 6/42 chance of an arachnotron in skill 1 etc
int MonsterChancesPerSkill[5][18] = {{6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,9,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0}};
                    
script 1 open
{
    int i,j,tid;
    int initialx,initialy,x,y;
    int gridwidth = 5;
    int gridheight = 3;
    int numMapSpots = numberOfInitialMapspots * gridwidth * gridheight;
    int total;
    int r;
    int spottid;
    int monsterindex;
    int tally;
    
    //get the points of initial mapspots
    for(i=1;i<=numberOfInitialMapspots;i++)
    {
        initialPoints[i-1][0] = getactorx(i);
        initialPoints[i-1][1] = getactory(i);
    }
    
    //remove those initial mapspots because they were only needed to get initial x/y locations
    for(i=1;i<=numberOfInitialMapspots;i++)
    {
        thing_remove(i);
    }
    
    //spawn mapspots (kinda pointless, why not just spawn monsters with no mapspots?)
    tid=1;
    for(i=0;i<numberOfInitialMapspots;i++)
    {
        for(y = initialPoints[i][1]; y>initialPoints[i][1]-(256.0*gridheight); y-=256.0)
        {
            for(x = initialPoints[i][0]; x<initialPoints[i][0]+(256.0*gridwidth); x+=256.0)
            {
                spawn("mapspot",x,y,0,tid,192);
                tid++;
            }
        }
    }
    
    //spawn random monsters to mapspots depending on skill
    for(spottid=1; spottid<=numMapSpots; spottid++)
    {
        total = 0;
        for(i=0; i<18; i++)
        {
            total+=monsterChancesPerSkill[gameskill()][i];
        }
        if(total!=0)
        {
            r=random(0,total-1);
            tally=0;
            for(i=0; i<18; i++)
            {
                tally += monsterChancesPerSkill[gameskill()][i];
                if(monsterChancesPerSkill[gameskill()][i] != 0 && r < tally)
                {
                    monsterIndex = i;
                    break;
                }
            }
            //each monster runs script 2, giving it its tid as a parameter
            spawnspot(monsters[monsterIndex], spottid, tid, 192);
            setthingspecial(tid, acs_executealways(2,0,tid));
            tid++;
        }
    }
    
}

script 2(int tid)
{
    int dead=0;
    int i;
    int total,tally,r,monsterIndex,thingIndex;
    While(dead==0)
    {
        if(getactorproperty(tid,APROP_health) <= 0)
        {
            for(i=0;i<18;i++)
            {
                if(checkactorclass(tid,monsters[i]))
                {
                    monsterIndex=i;
                    break;
                }
            }
            
            print(s:monsters[monsterIndex], s:" died ", d:monsterIndex);
            delay(100);

            total = 0;
            for(i=0; i<14; i++)
            {
                total+=spawnedItemChances[monsterIndex][i];
            }
            if(total!=0)
            {
                r=random(0,total-1);
                tally=0;
                for(i=0; i<14; i++)
                {
                    tally += spawnedItemChances[monsterIndex][i];
                    if(spawnedItemChances[monsterIndex][i] != 0 && r < tally)
                    {
                        thingIndex = i;
                        break;
                    }
                }
                spawn(items[thingIndex],getactorx(tid),getactory(tid),0);
                dead=1;
            }
        }
        delay(1);
    }
}

Share this post


Link to post

oh my, thank you gggmork! seems that i have really a lot to learn there.

spawning the mapspots may serve for something, in fact if used only once they are useless to spawn, studying and testing the code right now.

the chance of dropping a blur sphere and an invincibility one are just too hight, at the first test i got 5 blur and 3 invincibility, 1 berserk and 3 armor shard. edit: began to understand what you have done, i have to reduce a lot the chance to spawn a powerup and add an ammo spawn list.

also there is a weird demon that don't want to stop jumping all over the place lol, this seems to be bound to a specific mapspot, the monsters spawned from here have a z thrust movement set.

allmap died message there too, you putted it into the while loop without any conditional, so it keeps to print itself all over, and is pretty embarassing, hope to do not mess too much here trying to remove the problem. EDIT: solved i just ctrl-x, ctrl-v the print message after dead=1.

tryed 40 times in a row, maybe is bad luck but i am having a 400% chance to get one or more spider masterminds at starts on hmp and nearly zero zombieman and imps, also chaingunners and barons won't spawn. maybe i have to use a separate script to handle bosses.

a lot of monsters are spawning outside the map, i remember that you had a similar problem uh? searcing the thread now.

Share this post


Link to post

Ok, I edited the big code paste above and removed a few bugs.

Each mapspot will create a 5x3 grid of mapspots spaced 256 apart (necessary spacing to fit masterminds), so your map has to be big enough to allow for that... or you can mess with the grid size... otherwise they'll appear outside map.

Most variables towards top w/ lots of numbers are meant to be edited. I just put random numbers in there to test.

int MonsterChancesPerSkill[5][18] = {{6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,9,0,0},
                                     {6,0,0,4,3,2,9,0,0,0,9,0,0,0,9,0,0,0}};
row 1 is skill 1, row 2 is skill 2 etc.
Notice row 1 starts with 6,0,0,4
that means there's more likelyhood of the FIRST monster teleporting than the FOURTH monster (6 vs 4).
Look at the monsters in monsters[] array
FIRST monster is arachnotron (set to 6 probability), FOURTH is hellknight (set to 4 probability)
Lots are set to 0 (zero probability, which is why many aren't currently warping.
set to whatever you want.

like making the first row:
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
SHOULD make only baron of hells appear for skill 1, assuming I coded it right

{0,14,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0}
should make 2wice as many viles as cacodemons and no other monsters
etc

Share this post


Link to post

oh, now i understand it better, thank you again! i am going to edit a lot the grid to fit the shape of my level. you helped me really a lot :)

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×