Several ACS functions for reusable and more flexible code

Archive of the old editing forum
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.
User avatar
CodeImp
Posts: 456
Joined: Sun Dec 28, 2003 7:40 pm
Location: Netherlands
Contact:

Several ACS functions for reusable and more flexible code

Post by CodeImp »

I believe I suggested this a while ago, but it was kind of ignored or never viewed by you, Randy. However, let me try to explain it clearly this time;

It would be nice if you could add several simple functions to ACS that make it possible to get information from the map. For example, I can set a sector's light level, but I cannot read what a sector's light level is. Same for the floor/ceiling height/texture, I can set it, but I will never know what it currently is, because there are no such ACS functions that tell me. This would be very usefull to make reusable ACS scripts. No more hardcoding that sector height number or such.

Also what Graf Zahl mentioned a while ago; You could raise an elevator and assume it will be raised, but what if a player or monster was standing on the edge? The elevator gets stucked or even goes back down. Any other script that assumed it was up will never know it went wrong and possibly screw up the effect even more.

Functions I was thinking are for example;
Sector_GetDamage, Floor_GetHeight, Ceiling_GetHeight, Floor_GetTexture, etc.
Im sure I could come up with a whole bunch more of these, but just to give you an idea here.
User avatar
randi
Site Admin
Posts: 7749
Joined: Wed Jul 09, 2003 10:30 pm
Contact:

Post by randi »

These are fine, and I will implement them all for the next release except for the texture reading ones. ACS only has static strings, so no functions can return a string.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49229
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

GetTexture is not possible due to the way strings are handled. It can't return a texture index because that is not guaranteed to be preserved across savegames.
Some of the rest is desperately needed, though.


EDIT: Arrghh... Too late...
User avatar
HotWax
Posts: 10002
Joined: Fri Jul 18, 2003 6:18 pm
Location: Idaho Falls, ID

Post by HotWax »

Great news, Randy! Thanks!
User avatar
CodeImp
Posts: 456
Joined: Sun Dec 28, 2003 7:40 pm
Location: Netherlands
Contact:

Post by CodeImp »

Cool, thanks!
Just note that the ones I mentioned are not all of them, I could go by the list of ACS functions and think of a bunch more to get information about the map/things, just thought of a few as example ;)
User avatar
timmie
Posts: 199
Joined: Tue Jul 15, 2003 3:44 pm
Location: Vancouver, BC
Contact:

Post by timmie »

what if for the GetTexture one you had to pass in a string that would get filled in?
User avatar
HotWax
Posts: 10002
Joined: Fri Jul 18, 2003 6:18 pm
Location: Idaho Falls, ID

Post by HotWax »

Strings are NOT dynamic in ACS. Hence they can't be changed, period.

Let's say you compile this short script:

Code: Select all

script 1 OPEN {
  str MyText = "This is a string.";
  Print(s: "This is the second string in my script.");
  SpawnSpot("DoomImp", 61, 0, 0);
  MyText = "Would you believe this is the fourth?";
}
Here's what happens at compile time:

Code: Select all

Stringlist:
0: This is a string.
1: This is the second string in my script.
2: DoomImp
3: Would you believe this is the fourth?

Code:

script 1 OPEN {
  int MyText = s:0;
  Print(s:1);
  SpawnSpot(s:2, 61, 0, 0);
  MyText = s:3;
}
Notice the change from str to int. ACS doesn't really have two variable types, it only has ints. When you assign something to a string, ACS just puts a pointer to the string in the string table into the variable. Strings cannot be changed at runtime.

The best you could hope for here is a function that compares the texture name with a given string and returns 1 if it matches and 0 if it doesn't.

Here are a list of functions I think will be the most useful to mappers: (and are hopefully possible to implement)

// tag = 0 for activator's sector (if possible)
int GetSectorCeilHeight(int tag)
int GetSectorFloorHeight(int tag)
int GetSectorLightLevel(int tag)
int GetSectorFlags(int tag)
int GetSectorType(int tag)
// The following 3 return the special that is currently being executed on the specified property of the sector (if any), if that's possible
int GetSectorFloorAction(int tag)
int GetSectorCeilAction(int tag)
int GetSectorLightAction(int tag)
// lineid = 0 for activating line
int GetLineLength(int lineid) // Useful?
int GetLineFlags(int lineid)
int GetLineSpecial(int lineid)
// tid = 0 for activator
int GetThingSpecial(int tid)
int GetThingHeath(int tid)
int GetThingHeight(int tid)
int GetThingRadius(int tid)
int GetThingFlags(int tid) // See below
int GetThingState(int tid) // Returns a number based on state
// The texture things...
// A NULL string in the place of any texture denotes no texture
// Returns 1 if texture matches or 0 if not
int CompareFloorTexture(str texture)
int CompareCeilTexture(str texture)
int CompareLineTexture(int side, int segment, str texture)

I'm sure there's plenty I missed, so feel free to add to this.

About GetThingFlags: This would return the same number as DEHACKED displays for the flag byte. It could then be ANDed to determine if the thing has a particular flag. If there are multiple flag bytes (as I think there are), this function would need to be divided into multple functions, each one returning one of those bytes.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49229
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

HotWax wrote: // tag = 0 for activator's sector (if possible)


int GetSectorCeilHeight(int tag)
int GetSectorFloorHeight(int tag)
Considering slopes there should at least be a possibility to get the lowest/highest point of the respective plane.
int GetSectorFlags(int tag)
int GetSectorType(int tag)
Considering how sector specials are used there isn't much use for something like this. Light specials are cleared after being initialized, damage specials can be handled much better with Sector_SetDamage and the rest of the types doesn't have that much usefulness. For nearly everything there are better methods.
// The following 3 return the special that is currently being executed on the specified property of the sector (if any), if that's possible
int GetSectorFloorAction(int tag)
int GetSectorCeilAction(int tag)
int GetSectorLightAction(int tag)
The exact special cannot be returned because it isn't known after the action has started. Furthermore, the light action is actually never used! I don't know why Boom implemented it at all.
// lineid = 0 for activating line
int GetLineLength(int lineid) // Useful?
Who knows? But it can't hurt to have it, can it? ;)
int GetLineFlags(int lineid)
int GetLineSpecial(int lineid)
Add a GetLineArg(int lineid, int index) for completeness. This way a script could read a complete line special and store it for later use.
// tid = 0 for activator
int GetThingSpecial(int tid)
As above, add a GetThingArg(int tid, int index).
int GetThingHeath(int tid)
GetActorProperty(int tid, APROP_HEALTH)!
int GetThingHeight(int tid)
int GetThingRadius(int tid)
These should also be implemented as Get/SetActorProperty pairs.
And don't forget an APROP_MASS and APROP_SCALE. Real shrinking/expanding objects would be possible!

int GetThingState(int tid) // Returns a number based on state
Sorry, not much use for it without a proper definition what it should return. A state index by iteself is useless.
// The texture things...
// A NULL string in the place of any texture denotes no texture
// Returns 1 if texture matches or 0 if not
int CompareFloorTexture(str texture)
int CompareCeilTexture(str texture)
int CompareLineTexture(int side, int segment, str texture)

I'm sure there's plenty I missed, so feel free to add to this.
Better than nothing but it still can't handle the most important case of retrieving a texture for later use. :(
int GetThingFlags(int tid) // See below

About GetThingFlags: This would return the same number as DEHACKED displays for the flag byte. It could then be ANDed to determine if the thing has a particular flag. If there are multiple flag bytes (as I think there are), this function would need to be divided into multple functions, each one returning one of those bytes.
There are 4 flag words with some flags that are rather obscure. So at leas we need a second parameter to specify which flag word you want. And of course you'd also need a SetThingFlags(int tid, int index, int new) to change the flags. The danger I see here is that there isn't much that's easier to screw up than a thing's flags.

For a safer approach I suggest:

void SetThingFlag(int tid, int flagindex, bool flagvalue)
int GetThingFlag(int tid, int flagindex)

where flagindex is the index into a list of flags that are safe to change. Any flag that shouldn't be touched can be safely excluded from this list.


One final suggestion:

Sector_ClearSoundtarget(int tag) - clears the sound target of this sector
Thing_ClearSoundtarget(int tid) - clears the sound target of the sector this thing is in.

I find it annoying that monsters wake up immediately if they are spawned in a sector where a player's weapon could be heard an hour ago. This might also be of use when Strife's AI can be used in DECORATE. Strife makes much more sophisticated use of this feature and being able to clear the sound target for a sector might help a lot when using this special AI.
User avatar
CodeImp
Posts: 456
Joined: Sun Dec 28, 2003 7:40 pm
Location: Netherlands
Contact:

Post by CodeImp »

Graf Zahl wrote:
HotWax wrote: // tag = 0 for activator's sector (if possible)


int GetSectorCeilHeight(int tag)
int GetSectorFloorHeight(int tag)
Considering slopes there should at least be a possibility to get the lowest/highest point of the respective plane.
I think these would return the actual floor.ceiling heights as set in a map editor, which is MOST important. Another function could then return the slopeness, like;
int GetSectorSlopeAmountOrSomething(int tag)
Graf Zahl wrote:
// The texture things...
// A NULL string in the place of any texture denotes no texture
// Returns 1 if texture matches or 0 if not
int CompareFloorTexture(str texture)
int CompareCeilTexture(str texture)
int CompareLineTexture(int side, int segment, str texture)

I'm sure there's plenty I missed, so feel free to add to this.
Better than nothing but it still can't handle the most important case of retrieving a texture for later use. :(
Never will be possible in the way ACS currently works, but at least with these you can check for any texture names you could have possible set on that sector with one of your other scripts. It may help.
Graf Zahl wrote:clears the sound target of the sector this thing is in.
Hmm, that gives me another idea, maybe it already possible, otherwise it would be a nice addition:
int GetThingSectorTag(int tid) - returns the tag of the sector in which the thing currently is at.

Dont forget:
int GetSectorLightLevel(int tag) or something, which would also be very usefull for getting the current light level as set by map editor or as modified by one of the Light_ functions.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49229
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

CodeImp wrote: Dont forget:
int GetSectorLightLevel(int tag) or something, which would also be very usefull for getting the current light level as set by map editor or as modified by one of the Light_ functions.

Actually, that was already on Hotwax's list. ;)
User avatar
CodeImp
Posts: 456
Joined: Sun Dec 28, 2003 7:40 pm
Location: Netherlands
Contact:

Post by CodeImp »

Oh sorry, heh, didnt notice that one.
HotWax wrote:I'm sure there's plenty I missed, so feel free to add to this.
I dont know if Randy would like to dive the ACS functions listing himself and think of new ones or have us do so and discuss what would be usefull?
User avatar
Risen
Posts: 5263
Joined: Thu Jan 08, 2004 1:02 pm
Location: N44°30' W073°05'

Post by Risen »

What happens if multiple tagged items have different properties? For example, what would GetSectorLight return on two sectors of different light levels with the same tag?
User avatar
HotWax
Posts: 10002
Joined: Fri Jul 18, 2003 6:18 pm
Location: Idaho Falls, ID

Post by HotWax »

Graf Zahl wrote:Sorry, not much use for it without a proper definition what it should return. A state index by iteself is useless.
I took it as understood that there would need to be #defines associated with this function. Example:

Code: Select all

#define StateInvalid 0
#define StateSpawn 1
#define StateSee 2
#define StateMelee 3
...
It would also be nice to have a second function that returns the offset from state start, so that you know exactly what frame the Thing with the given TID is currently in.

And of course, the ability to jump to a state and/or frame from ACS would allow for much greater utility for DECORATE monsters.

Everything else in your post I agree with. Particularly the addition of actor properties for height, radius, mass, etc. Once again, that would allow people to create more useful and varied monsters.

[edit]Oh, just thought of a new batch of thing functions. Most if not all of these are probably impossible as the game stands now, but I think they should be implemented because it would greatly enhance what a mapper is able to do via scripting.

// All of these return 0 if the value would otherwise be invalid (no last attacker, or target has TID of 0, etc)
int Thing_LastAttacker(int tid) // Returns the TID of the Thing which last damaged this Thing
int Thing_Owner(int tid) // Returns the TID of this Thing's owner (The Thing that spawned it), if applicable
int Thing_Target(int tid) // Returns the TID of this Thing's current target
int Thing_LastAttacked(int tid) // Returns the TID of the last Thing this Thing attacked
int Thing_LastSpawned(int tid) // Returns the TID of the Thing most recently spawned by this Thing
int Thing_Killer(int tid) // Returns the TID of whatever killed this Thing (assuming this Thing is dead) -- might be redundant with Thing_LastAttacker?

With the utility of, for example, Thing_LastAttacker (and possibly Thing_Owner if the last attacker was a projectile), LWM could have weapons that accurately decay over time when dealing damage, not just when an enemy is killed. She'd also be able to determine if the player is the one doing the damage or if the monster got caught in crossfire, or got hit by a hireling/spell/whatever.
Last edited by HotWax on Tue May 04, 2004 4:07 pm, edited 1 time in total.
User avatar
CodeImp
Posts: 456
Joined: Sun Dec 28, 2003 7:40 pm
Location: Netherlands
Contact:

Post by CodeImp »

Risen wrote:What happens if multiple tagged items have different properties? For example, what would GetSectorLight return on two sectors of different light levels with the same tag?
How about:
int GetSectorLightLevel(int tag, int selection)

Where selection can be:
0 - Return lowest light level of all tagged sectors
1 - Return highest light level of all tagged sectors
2 - Return average light level of all tagged sectors
3 - Return -1 in case levels are different in all tagged sectors

Good idea, bad?
User avatar
HotWax
Posts: 10002
Joined: Fri Jul 18, 2003 6:18 pm
Location: Idaho Falls, ID

Post by HotWax »

I think that an extra parameter to determine what happens in multiple-target situations is a good idea and certainly can't hurt. I was assuming above that the mapper would properly use these on unique tags/TIDs/lineids, but this addition would allow for more out of the same function, and provides a default behavior when somebody (accidentally or intentionally) misuses them.

Just a few slight changes I'd recommend:

0 (default) - Average light level
1 - Lowest light level
2 - Highest light level
3 - Light level or -1 if light levels are different between ANY sectors (not all)

Similar properties should in fact be added to all the stuff we've suggested thus far.. (in fact that provides a point for Thing_GetHealth -- it could return the average health of a slew of enemies :P)

Out of curiosity, what is the behavior of GetActorProperty when multiple monsters with the same TID exist?
Locked

Return to “Editing (Archive)”