Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. This forum is archived - please use this set of forums to ask new questions.
1. The player meets an enemy & engages
2. The enemy takes some damage
3. When the enemy has taken a specified amount of damage (or when its health drops to a specified level, whichever is easier) it is teleported to another location
I want to use ACS to determine when the enemy has taken the necessary damage to teleport it away. I have searched the forums and the wiki, and I've not found the specials necessary for this task.
I'd greatly appreciate any help in this matter.
[For reference, my script currently teleports the enemy after a specified duration, which won't really work if the player can destroy the enemy before that duration ends:
ReX wrote:I'll give it a shot & report back. Graf, I'll make sure I put the delay in there.
I implemented the following code, which compiled fine but does not work as intended. Specifically, the enemy does not teleport away when its health drops below the specified level. Any suggestions?
It's not a problem in the current state because the else stuff is commented out, but that's a very bad place for your delay, it should be in the same block as restart, just before restart.
As for why the script doesn't seem to work; I suggest printing some message to check what's happening. E.g.:
{
int actorhp = GetActorProperty (18, APROP_HEALTH);
PrintBold(s:"Gargantua health: ", i:actorhp);
if (actorhp <= 6500)
{
Log("s:Teleporting");
TeleportOther (18, 20, 1); //Teleports Gargantua out of Test Lab
}
else
{
delay (18);
restart;
}
}
This way you'll get to know how much health the script believes the monster has, and you'll be warned in the log if it attempts to teleport. With these information, you can quickly check for two possible map errors:
#1. Something else is tagged 18 accidentally and the script doesn't look for the health of the actual monster, but for some other map thing with the same TID.
#2. The monster does attempt to teleport, but the teleportation fails for some reason (keep in mind that monsters are normally allowed to telefrag!).
Gez wrote:As for why the script doesn't seem to work; I suggest printing some message to check what's happening. E.g.:
[example code]
This way you'll get to know how much health the script believes the monster has, and you'll be warned in the log if it attempts to teleport. With these information, you can quickly check for two possible map errors:
#1. Something else is tagged 18 accidentally and the script doesn't look for the health of the actual monster, but for some other map thing with the same TID.
#2. The monster does attempt to teleport, but the teleportation fails for some reason (keep in mind that monsters are normally allowed to telefrag!).
I used the code you suggested, with a couple of modifications, as follows:
{
int actorhp = GetActorProperty (18, APROP_HEALTH);
PrintBold(s:"Gargantua health: ", i:actorhp);
if (actorhp <= 6500)
{
Log(s:"Teleporting");
TeleportOther (18, 20, 1); //Teleports Gargantua out of Test Lab
}
else
{
delay (18);
restart;
}
}
At the start of the battle, the health of the monster is correctly displayed. Thereafter, I am unable to see its health. [I realize I can implement a health status bar, but I'm trying to avoid more features.] The "teleporting" log fails to appear, probably because the script is failing to trying to teleport the enemy. The end result is that the enemy does not teleport, and I'm eventually able to destroy it in that room.
As for your other points, I checked and the Gargantua is the only thing with TID 18. The destination mapspot (TID 20) is at a location with plenty of room for the Gargantua to spawn, and there is no possibility of something blocking the spawning. It's also unique. Moreover, if I use the previous script and have the creature teleport out after a specified duration, the teleporting part of the script works just fine. In fact, I went back to the original script, and the teleporting worked just as intended:
{
int actorhp;
do
{
actorhp = GetActorProperty (18, APROP_HEALTH);
PrintBold(s:"Gargantua health: ", i:actorhp);
delay(18);
} while (actorhp > 6500);
Log(s:"Teleporting");
TeleportOther (18, 20, 1); //Teleports Gargantua out of Test Lab
}
It's a different approach, instead of restarting the script we loop on a condition (using the do while structure; you could use a while instead but in this case I felt that the do while was the more elegant approach as it avoids having to query the monster's health in two different places in the code).
{
int actorhp;
do
{
actorhp = GetActorProperty (18, APROP_HEALTH);
// PrintBold(s:"Gargantua health: ", i:actorhp);
delay(18);
}
while (actorhp > 6500);
// Log(s:"Teleporting");
TeleportOther (18, 20, 1); //Teleports Gargantua out of Test Lab
}
However, I'm trying to understand the logic. (Or perhaps I simply don't understand the syntax.) I imagine this is doing the following:
1. Get the enemy's health
2. Check to see if the enemy's health is > 6500
3. While this is true, loop back to the DO statement (i.e., Step 1)
4. When this is not true, teleport the enemy away
Intuitively, I'd have thought the WHILE statement would have been at the start of the logic. At any rate, it works, so I'm very grateful to you.
The do, while loop works exactly the same as the while loop, except the code is executed before the check is done. So what Gez' code does is essentially stalls the teleport until health is under 6500.
ReX wrote:Intuitively, I'd have thought the WHILE statement would have been at the start of the logic. At any rate, it works, so I'm very grateful to you.
Yes, that's what I meant with the difference between "while" and "do while". As Gutawer points out, the "do while" loop makes the check at the end instead of the beginning.
With a while loop, I'd have to do something like this:
And so it makes me get the actor hit points in two different places in the code. It's never a good idea to have to duplicate the same instruction when you can avoid it, because it means that if later for some reason you have to change it, then you have to remember to change all the places that have been duplicated.
Anyway, the logic is just that the script will always eventually teleport in its first running instance (provided the monster's health does decrease over time, of course), and it just waiting until the condition is met. I don't know why the restart didn't work (that might deserve reporting as a bug, honestly) but with a while loop you don't need to restart, so problem solved.