Making a weapon/monster with an outdoors only attack

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
mrspeaker
Posts: 21
Joined: Mon Dec 14, 2020 10:24 pm

Making a weapon/monster with an outdoors only attack

Post by mrspeaker »

What it says in the title. I want to make a monster with an attack that calls down lightning for example, but can only be used if the target is outdoors. Is that possible?
There are ways to check if the target is underwater by checking waterlevel, but is there a way to check if a monster is outdoors or indoors, as in, under a ceiling or exposed to the sky?
Last edited by mrspeaker on Tue Nov 09, 2021 1:26 pm, edited 1 time in total.
User avatar
nova++
Posts: 177
Joined: Sat Sep 04, 2021 3:13 am

Re: Making a weapon/monster that with an outdoors only attac

Post by nova++ »

Are you willing to use ZScript? You can grab the target's current sector and check its ceiling texture, I believe. I'm not in a good spot to try it myself right now (I actually need to do something similar for my project at some point), but I am fairly sure it's possible.
User avatar
Virathas
Posts: 228
Joined: Thu Aug 10, 2017 9:38 am

Re: Making a weapon/monster that with an outdoors only attac

Post by Virathas »

Just a quick note, if Zandronum compatibilty is required ACS can be used for that (I did that in my project, both an air strike and thunderstorm). The base gist is the same, to check an actor's ceiling texture.
mrspeaker
Posts: 21
Joined: Mon Dec 14, 2020 10:24 pm

Re: Making a weapon/monster that with an outdoors only attac

Post by mrspeaker »

nova++ wrote:Are you willing to use ZScript? You can grab the target's current sector and check its ceiling texture, I believe. I'm not in a good spot to try it myself right now (I actually need to do something similar for my project at some point), but I am fairly sure it's possible.
Unfortunately I only know how to use decorate. I have zero scripting/coding experience.
Virathas wrote:Just a quick note, if Zandronum compatibilty is required ACS can be used for that (I did that in my project, both an air strike and thunderstorm). The base gist is the same, to check an actor's ceiling texture.
How did you manage to do it, if you don't mind me asking? I'm very interested especially in the airstrike since my idea was for a monster that could call an artillery strike on bosses.
User avatar
Virathas
Posts: 228
Joined: Thu Aug 10, 2017 9:38 am

Re: Making a weapon/monster with an outdoors only attack

Post by Virathas »

Well, copying straight from my mod the scripts:
DECORATE

Code: Select all

Actor AirStrikeBeacon
{
Radius 16
Height 16
Mass 10
Speed 4
BounceFactor 0.0
-SHOOTABLE
-CANBLAST
States
{
Spawn:
	MINE A 0 A_Gravity
	BEAC ABABA 35
	BEAC A 0 ACS_NamedExecuteAlways("AirStrikeTest",0)
	goto idle
Idle:
	BEAC AB 10
	Loop
Death:
	BEAC A 1 A_FadeOut(0.015)
	Loop
}
}
ACS

Code: Select all

script "AirStrikeTest" (void)
{
	int CenterTID = ActivatorTID();
	int MissileID = UniqueTID();		
	
int timepast = 0;
int failcount = 0	;

	while ( timepast < 400 )
	{
		if  (failcount >= 100)
		{
			failcount = 0;
			delay(5);
			timepast++;
		}

     int x = GetActorX(CenterTID) + random(-768.0, 768.0);
     int y = GetActorY(CenterTID) + random(-768.0, 768.0);
     int z = GetActorCeilingZ(CenterTID);
	if (!(Spawn("Airstrikemissile", x, y, z, MissileID)))
	{
		failcount++;
		continue;
	}
	else
	{
		if ((CheckActorCeilingTexture(MissileID,"F_SKY1")) || (CheckActorCeilingTexture(MissileID,"F_SKY2")) || (CheckActorCeilingTexture(MissileID,"F_SKY3")) || (CheckActorCeilingTexture(MissileID,"F_SKY4")) || (CheckActorCeilingTexture(MissileID,"SKY1")) || (CheckActorCeilingTexture(MissileID,"SKY2")) || (CheckActorCeilingTexture(MissileID,"SKY3")) || (CheckActorCeilingTexture(MissileID,"SKY2A")) || (CheckActorCeilingTexture(MissileID,"SKYFOG")) || (CheckActorCeilingTexture(MissileID,"SKYFOG2")) || (CheckActorCeilingTexture(MissileID,"SKY")) || (CheckActorCeilingTexture(MissileID,"F_SKY")))
		{
			if 	((GetActorCeilingZ (MissileID) - GetActorFloorZ (MissileID)) < 16)
			{
				Thing_Remove(MissileID);
				failcount++;
				Continue;
			}
			else
			{
				SetActorPosition(MissileID, x,y,GetActorCeilingZ(MissileID) - 4.0, 0);
			}
		}
		else
		{
			Thing_Remove(MissileID);
			failcount++;
			Continue;
		}
		Thing_ChangeTID(MissileID, 0);
		delay(5);
		timepast++;
	}
	}
		Thing_Remove(CenterTID);
}
What it does in short: A beacon after a short while summons a few hundred missiles from sky in a significant radius.

What it does in long: The script is called from the decorate actor once, and only once.
The script first sets a TID to the actor, to be able to reference it easily.
The timepast variable is used to count how many missiles have been already spawned
The failcount is a safety variable, in case there are no valid places to spawn a missile, it will eventually terminate the script.
"if (!(Spawn("Airstrikemissile", x, y, z, MissileID)))" <- this both spawns a missile as well as checks for success. It adds a TID to the missile to reference it later.
The latter large "if" block is the thing you want the most - this tests if the location where missile spawns has the sky. If not, the missile is removed.

In your case the "beacon" should be spawned at the player's location, and then a similar script should be ran.

Hope it isn't too confusing :P
User avatar
Matt
Posts: 9670
Joined: Sun Jan 04, 2004 5:37 pm
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: Making a weapon/monster with an outdoors only attack

Post by Matt »

If you want to avoid both ACS and Zscript, one more option is to shoot an invisible, zero-damage, no-blood ripper projectile straight up really fast. If it explodes, it's hit a ceiling and should give the shooter an item marking the shooter as being under a ceiling; if it hits sky, it just disappears without doing anything further.

The weapon can then be set to, upon any shot:
1. Delete the item from the user's inventory
2. Shoot the invisible projectile
3. Wait a moment
4. Jump to an abort state if the item is found


That said, if you're willing to convert the weapon code to ZScript (basically just add a bunch of semicolons, add a version number, change a few formatting things for damage and put the properties/flags in a "default" block), you can basically skip to step 4 with something like

Code: Select all

MJOG A 0 A_JumpIf(CurSector.GetTexture(CurSector.ceiling)==SkyFlatNum,"summonlightning");
goto fail;
mrspeaker
Posts: 21
Joined: Mon Dec 14, 2020 10:24 pm

Re: Making a weapon/monster with an outdoors only attack

Post by mrspeaker »

Thanks for the help! Your posts gave me an idea and I think I found an easy way to do this.

Monster shoots an invisible non-damaging missile on another valid monster (A_CheckLOF is called before to ensure he doesn't shoot something else). Upon hitting the target, it spawns another missile that has the +SKYEXPLODE flag, is also invisible and non-damaning, ripping, goes straight up and has both a Death and a Death.Sky states. So if it hits a ceiling, nothing happens and if it hits the sky, it works normally. What do you think? Will it work?

EDIT: It works. Now I just need to fine-tune it and I'll have a spotter marine that calls in artillery strikes on bosses.

Return to “Scripting”