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

Player In Sector iterator broken

Recommended Posts

Top-down view of issue.

Problem in action, broken iterator reads "4".

Long story short, I have walkable lasers and a 16-px zone around each laser to make sure the player can't get away with walking on them and not getting hurt (under z-axis conditions ofc, and it works great). I'm debating just making them non-solid, but that's not the problem I have. The problem I have is the little actors in the top-down image: they're Actor Enters Sector and Actor Exits Sector actors, attached to their respective scripts that adds a 1 when the enter actor is triggered, and subtracted 1 when the exit actor is triggered. When testing, I found that straferunning through these is just too fast for the engine to register, and either an exit actor or enter actor doesn't activate, resulting in an unreal offset (I was able to make the iterator get to -10 at one point, just running back and forth a certain way). Removing the enter and exit actors in the 1px zone didn't help either (I assumed the 1px was too small to fit in a tic, but the same problem still happened). I also just realized each of these sectors would need their own tags, but running through might still result in this iterator error. I'll cross that bridge as I get to it. (Yes, I want to make the wad multiplayer compatible later on, or else I would've found an alternative much earlier on.)

The reason I need a player iterator:

Spoiler

do
{
if(GetActorZ(1000 + n) <= -5046272 && playerInSector >= 1)
{
SectorDamage(52, laserHurt, "Fire", "", DAMAGE_PLAYERS
| DAMAGE_NONPLAYERS | DAMAGE_IN_AIR);
SectorDamage(53, laserHurt, "Fire", "", DAMAGE_PLAYERS
| DAMAGE_NONPLAYERS | DAMAGE_IN_AIR);
}
Delay(1);
Print(d:playerInSector);
} while (TRUE);

laserHurt is an integer, earlier defined based on difficulty level.
playerInSector is the iterator in question.
Tag 52 is the 1px zone, tag 53 are the 16px zones.
the DAMAGE_IN_AIR flag is used because of the Doom quirk that sitting on the edge of the 1px doesn't inflict damage. I'm assuming you're not actually in the sector, and there's just a 16px safe zone on the edge of every sector (something I solved in the top-down picture).

If the player check didn't exist, anything would get hurt if the player sat below that z axis (ex. walking on the floor), triggering all the laser sectors. Also, the lasers and 3d floors under them (making it walkable) sit at that Z axis value, and without the z check, anything existing in the sectors would get hurt (and I only want pain to inflict when touching the laser).

Share this post


Link to post
CooBlu said:

I also just realized each of these sectors would need their own tags, but running through might still result in this iterator error. I'll cross that bridge as I get to it. (Yes, I want to make the wad multiplayer compatible later on, or else I would've found an alternative much earlier on.)

...

If the player check didn't exist, anything would get hurt if the player sat below that z axis (ex. walking on the floor), triggering all the laser sectors. Also, the lasers and 3d floors under them (making it walkable) sit at that Z axis value, and without the z check, anything existing in the sectors would get hurt (and I only want pain to inflict when touching the laser).

Interesting idea, that laser thing. However, I think that your implementation of giving damage isn't perfect. I assume that you want any actor (be it a monster or a player) to take damage, if and only if said actor touches the laser. Instead of your currect method, which is to run an infinite checking script for an "iterator", I suggest to launch a separate script for each actor stepping in the laser's effective area, and terminating the script when the actor leaves that area. Then you can use Thing_Damage2 to deal damage only to this actor (only check for his Z position). Use linedef actions to launch the respective scripts - Enter Sector/Exit Sector actions may fail, but linedef actions never fail.

In order to check if the actor is still in the laser's horizontal area, you might need to assign a "checking" inventory type (declared in DECORATE) to the actor. I've imagined it like this:

SCRIPT 101 (void) { // "Enter" script for the laser's area, called via "ACS_ExecuteAlways" from a linedef.
  while(1) {
    if(CheckInventory("myDummyInventory")) {
      TakeInventory("myDummyInventory",1);
      terminate;
    }
    if(GetActorZ(0) <= -5046272) Thing_Damage2(laserHurt);
    Delay(1);
  }
}
SCRIPT 102 (void) { // "Exit" script for the laser's area, called via "ACS_ExecuteAlways" from a linedef.
  GiveInventory("myDummyInventory",1);
}
I can see a possible problem with ensuring that the exit linedef is always properly crossed, but it should be solvable too.

EDIT: Corrected my code.
EDIT2: Again.

ANOTHET EDIT: Here is a quick guide how to declare "myDummyInventory" in DECORATE. It's really simple. Open your wad in SLADE3, create a new lump named "DECORATE" and put this text into it:
actor myDummyInventory : inventory { inventory.maxamount 1 }
Maxamount will, obviously, forbid any actor to have more than 1 of this inventory.

Share this post


Link to post

The inventory system looks great on screen, but the GiveInventory script seems to get overridden almost immediately and as a result, all sectors are affected. (1 means the script is in affect, I nestled that Print in the z check if-statement.) It's really strange, and I haven't been able to debunk this.

I went back to my original idea of making the lasers pass-throughable, removing the 1px sector and just leaving the area where pain is given. I also introduced a new Thing as a sort of final check, Actor Hits Floor. It gets its own script, to make sure the pain script isn't being ran multiple times at once. (Script 20, Actor Hits Floor)

Spoiler

script 20 (void)
{
if (playerInSector[PlayerNumber()] == TRUE)
terminate;
ACS_ExecuteAlways(18, 2);
}

playerInSector is an array for each player. It was a quick fix for the moment, as monsters don't apply to this. I'll try incorporating the inventory idea, because as far as I know monsters can have an inventory which would make everything work 100%.

Script 18 is the pain script.

I did quick run-throughs, checking the amount of instances of the scripts at any time, if pain was inflicted in the right sectors, etc., and it works!

Script 18 (Actor Enters Sector)
Spoiler

script 18 (void)
{
playerInSector[PlayerNumber()] = TRUE;
int diffDamage;

if (GameSkill () >= SKILL_HARD)
diffDamage = 10;
else if (GameSkill () == SKILL_NORMAL)
diffDamage = 7;
else
diffDamage = 5;

while (playerInSector[PlayerNumber()] == TRUE)
{
if(GetActorZ(0) <= -5242880) //-80 on the Z axis
{
DamageThing(diffDamage);
}

Delay(2);
}
}

Something I should point out, scifista42 mentioned Thing_Damage2 as a way to inflict damage. That function requires a TID, whereas DamageThing damages whatever triggered the script.

Script 19 (Actor Exits Sector)
Spoiler

script 19 (void)
{
playerInSector[PlayerNumber()] = FALSE;
}

EDIT: Updated code, changed z check and added difficulty modifier in Script 18.

Share this post


Link to post

Sorry for confusing DamageThing with Thing_Damage2 in my previous post, my mistake.

CooBlu said:

The inventory system looks great on screen, but the GiveInventory script seems to get overridden almost immediately and as a result, all sectors are affected. (1 means the script is in affect, I nestled that Print in the z check if-statement.)

I don't understand.

Do the "Sector Enter/Exit" special things even work for monsters? Once again I recommend using linedef actions to launch scripts (you can try LineSide), AND dummy inventory instead of a global array.

I suggest this improved, universal script. Let it be called by linedefs around the pain area (ACS_ExecuteAlways action), and allow activation by monsters. I've added another dummy inventory type, "ScriptRunning", to check for multiple instances of the same script and terminate them. LineSide() is used to determine whether the player is leaving the pain area or entering it.

SCRIPT 18 (void) {                                       // One universal script
  if(LineSide()==LINE_BACK) {                            // Actor is leaving the area
    GiveInventory("StopPain",1);                         // Inform another instance of the script that it should stop dealing damage
    terminate;                                           // End
  }                                                      // LineSide()!=LINE_BACK -> Actor is entering the area
  if(CheckInventory("ScriptRunning")) terminate;         // Another instance of the script is already running -> End
  GiveInventory("ScriptRunning",1);                      // No new instance of this script will be able to run for this player/monster
  while(!CheckInventory("StopPain")) {                   // Should I stop dealing damage?
    if(GetActorZ(0) <= -5046272) DamageThing(laserHurt); // Should I damage the player?
    Delay(1);                                            // Waiting 1 tic
  }
  TakeInventory("StopPain",1);                           // Allow damage to be dealt next time when player enters the sector
  TakeInventory("ScriptRunning",1);                      // Allow new instances of this script to run
}
DECORATE:
actor StopPain : inventory { inventory.maxamount 1 }
actor ScriptRunning : inventory { inventory.maxamount 1 }
This script has a definite advantage that it should work independently for all players and monsters in the map. Now just add your difficulty damage modifier there.

Share this post


Link to post

Hey, it works great. My previous problem must have had something to do with linedef triggering, but LineSide() works. You've been a big help, scifista42!

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
×