Jump to content
The Dark Mod Forums
Sign in to follow this  
Dragofer

New Entity: Teledoor

Recommended Posts

Quote

Can it chase you through?

Nope, that's a size too large for me I believe - would probably have to identify an area with enough pathable space to teleport the AI to. Something that I could possibly get to work is, when there's a level 5 alerted AI chasing the player:

  • stop the door from working. But imo doesn't really make sense that you can't open certain doors because you're being chased.
  • play a silent alarm on the other side of the door that alerts the AIs there. This can mess up something cramped like a ship interior.

I remember a discussion from jarredmitchel's ship, which also has teleports between interior & exterior - one solution I offered was to do nothing, because most players quickload anyway when they get spotted.

Edit: hm, could maybe ask the mapper to place a teleportation entity for chasing AIs. But what if there are 2-3 AIs chasing the player?

Edited by Dragofer
  • Like 1

Share this post


Link to post
Share on other sites

Very nice work!

About AI going through, teleports are the answer indeed, Doom 3 has a tons of AI's teleporting into the levels, if i'm recalling well sometimes more than one in the same place.

One way that I think off to make sure multiple AI teleport into the map, in the same spot, is to create the idea of a cue, no need for multiple teleports, just don't teleport another AI in, while one AI or the player, is in the teleporter or very near it. You can give the teleporter a trigger box or a idbound area and test if a AI is within the volume.

Btw i'm using my C++ mind here not sure if possible or as easy with DoomScript...

Edited by HMart

Share this post


Link to post
Share on other sites

I'd leave that for all doors, windows, vents etc. that are inaccessible to AI then, at least for now.

On 2/7/2020 at 6:07 PM, Dragofer said:

I remember a discussion from jarredmitchel's ship, which also has teleports between interior & exterior - one solution I offered was to do nothing, because most players quickload anyway when they get spotted.

That's not a good assumption IMO. There are ghosters and perfectionists, sure, but your map should always support "resetting the simulation", running away from AI and waiting for things to calm down. Otherwise it's not really good level design because im-sim part of the equation falls apart every time AI is alerted.

Edited by peter_spy

Share this post


Link to post
Share on other sites

You guys rock. :)

Even though I think this kind of thing should be used sparsely. For me, it's much more fun to move around in a connected world, than warp into a different one all the time. I can see its uses, but, I also think that you shouldn't be thrown out of the mission focus, so to speak.

  • Like 2

Share this post


Link to post
Share on other sites

Well having thought on it I can probably do something inside Doomscript, given enough input from the mapper:

1) Ask the mapper to draw an inactive trigger_touch brush in front of each teledoor. It should represent the max range from which an AI would pursue the player through the door. Also ask the mapper place a 2nd teleport entity and maybe also a 3rd in case the 1st teleport spot is occupied.

2) Every time the teledoor gets activated its trigger_touch brush runs for one frame to detect all AIs and their alert states.

3) For any alert 5 (chasing) or alert 4 (agitated searching) AI, calculate their distance to the door and assign a time taken to reach it. Alert 4 AIs have to be closer to the door and take more time to reach it.

4) If the player is still on the other side of the door after the time has elapsed, the AI tries to teleport. Prefer the 1st teleport spot, but use the 2nd spot if the 1st spot is occupied. Run the trigger_touch before each teleport to make sure there are no AIs or moveables standing on the targeted spot. If occupied, wait 1s and try again.

5) After teleporting, check the AI's alert level every 3s. If they're back down to alert 1 (idle, but alert), let them walk back to the teledoor and open it. The AI gets teleported back to the other side - Skyrim has them fade out first - if any of the teleportation spots are free. If they're occupied, keep checking every 3s

6) Find what path node the AI was targeting and reassign it so the AI resumes his patrol.

So it's clear this is a larger project than just getting a new kind of teleportation entity, and there's more that can go wrong. I'd probably be better off learning C++ and doing this properly with all the extra commands available in the source code..


And yeah, chakkman makes a good point about physically connected spaces being preferrable, even if teleportation has its uses. My current WIP ship uses these teledoors to get a more spacious interior that has more content and is less prone to the pathing issues seen in one-piece ships. Imo the benefits outweigh the downsides by a good amount in this case.

An alternative that I'm using for another WIP btw is my mass_teleport script: 2 identical areas with a large trigger_touch brush that can be activated to detect & call teleportation on all moving entities except AIs.

  • Like 1

Share this post


Link to post
Share on other sites
On 2/7/2020 at 8:36 PM, Dragofer said:

play a sound globally via script. However, as far as I'm aware this will loop until you stop it after x amount of time, and I don't know of a way to check how long the sounds in a soundshader are

I think if you start sound from script, it will loop only is the shader has looping keyword.

What happens if you just call startSound? I think you can call it on any entity, not only on the current one. Also, this event returns the duration of the sound.
 

  • Thanks 1

Share this post


Link to post
Share on other sites

As for AI: they can use elevators. Elevator is a special multi-station thing such that AIs know how to move between stations. In fact, elevator is even more complicated than teledoor: AI knows how to call it, and how to wait while being on it. It is quite likely that this elevator system can be adapted here, so that guards could chase through teledoors without problem.

If this does not work, then it's better just do nothing. The support for elevators took about 1000-2000 lines of complicated C++ code, I doubt this teledoor feature is valuable enough to spend so much time and effort on it.

Share this post


Link to post
Share on other sites

This is a really cool feature, thanks for making it and releasing it Dragofer! I do think that it should be used sparingly, but in some cases such as with ships and smaller interiors it makes sense. I never really felt like the immersion was too badly affected in Skyrim due to their door system, as a caveat TDM is a very different game though. It does make the job a whole lot easier for mappers for those special cases.

  • Thanks 1

My Fan Missions:

   Series:                                                                           Standalone:

Chronicles of Skulduggery 1: Pearls and Swine                     The Night of Reluctant Benefaction

Chronicles of Skulduggery 2: A Precarious Position              Langhorne Lodge

Chronicles of Skulduggery 3: Sacricide [WIP]

 

 

 

Share this post


Link to post
Share on other sites

 

10 hours ago, stgatilov said:

What happens if you just call startSound? I think you can call it on any entity, not only on the current one. Also, this event returns the duration of the sound.

Thanks, that's got me on the right track. There's startSound and startSoundShader - the wiki says startSound is to be preferred, but it's been behaving oddly when I was working with it. It also has an odd 3rd parameter called netSync that's never been mentioned anywhere on thedarkmod.com. Seeing that it always returns 0 as the duration caused me to look for another command: startSoundShader, which works flawlessly out of the box.

So, the teledoor has been refined:

  • the teledoor now uses snd_open and snd_close instead of asking for speakers. snd_open gets played on this teledoor, while snd_close plays on the other side's teledoor if the mapper has targeted it, otherwise snd_close plays in the player's head. There are now no more custom spawnargs.
  • the teledoor now identifies up to 2 door handles via their spawnclass, rather than triggering all bound entities (this was after getting blocked by a bug in trying to identify them via their "inherit" property)

Also experimented with making it lockable, but the road got blocked at calling the use_action_script. As I understand the use_action_script should get called when I use any inventory item on it, but the items seem to only use themselves on themselves. I'm guessing when an item is used it checks whether an eligible entity like a mover_door is in your frob highlighter?

 

9 hours ago, stgatilov said:

As for AI: they can use elevators. Elevator is a special multi-station thing such that AIs know how to move between stations. In fact, elevator is even more complicated than teledoor: AI knows how to call it, and how to wait while being on it. It is quite likely that this elevator system can be adapted here, so that guards could chase through teledoors without problem.

If this does not work, then it's better just do nothing. The support for elevators took about 1000-2000 lines of complicated C++ code, I doubt this teledoor feature is valuable enough to spend so much time and effort on it.

For an in-Doomscript solution I'm imagining turning this into a hybrid between a func_mover and an elevator button, which spawns a symbolic elevator that tells the AI to wait x seconds before it can move from its new position. Well.. it sounds like the kind of thing that you can spend ages tweaking & polishing, and as has been said it's mainly for special situations. I'd rather get my spawnarg-controlled func_mover ready before going down this route.

Share this post


Link to post
Share on other sites
5 hours ago, Dragofer said:

Thanks, that's got me on the right track. There's startSound and startSoundShader - the wiki says startSound is to be preferred, but it's been behaving oddly when I was working with it. It also has an odd 3rd parameter called netSync that's never been mentioned anywhere on thedarkmod.com. Seeing that it always returns 0 as the duration caused me to look for another command: startSoundShader, which works flawlessly out of the box.

The netSync parameter specifies whether the sound should be started for this player only, or for all players in a multiplayer session. I'm afraid it cannot be removed at this moment. Existing scripts often call it by passing false, although true would work too.

I cannot understand why startSound returns zero for you. Looking at the code, startSound internally calls startSoundShader and returns the value it gets from it. Moreover, I put breakpoint into startSound and verified that it returns some positive numbers.

Share this post


Link to post
Share on other sites

@stgatilov thanks for finding that out, this kind of thing can go on the wiki later on.

Quote

I cannot understand why startSound returns zero for you. Looking at the code, startSound internally calls startSoundShader and returns the value it gets from it. Moreover, I put breakpoint into startSound and verified that it returns some positive numbers.

Neither do I. I've made a simple map script yesterday that should automatically play the start, loop and end sound of an elevator at the location of player1 and prints sound durations to the console. If I use the thread with startSound, no sound is played and it returns 0 as the duration of the start sound, while if I use the thread with startSoundShader everything works smoothly:

Spoiler

void test_startSound()		//doesn't work: no sound is heard, sound_duration1 is 0 and script stops at sys.wait(sound_duration1);
{
float	sound_duration1 = $player1.startSound("elevator03_start", SND_CHANNEL_ANY, 0);
	sys.println("sound duration1 is " + sound_duration1 + "s");
	sys.wait(sound_duration1);

float	sound_duration2 = $player1.startSound("elevator03_loop", SND_CHANNEL_ANY, 0);
	sys.println("sound duration2 is " + sound_duration2 + "s");
	sys.wait(sound_duration2);
	$player1.stopSound(SND_CHANNEL_ANY, 0);

float	sound_duration3 = $player1.startSound("elevator03_end", SND_CHANNEL_ANY, 0);
	sys.println("sound duration3 is " + sound_duration3 + "s");
	sys.wait(sound_duration3);
}


void test_startSoundShader()		//works
{
float	sound_duration1 = $player1.startSoundShader("elevator03_start", SND_CHANNEL_ANY);
	sys.println("sound duration1 is " + sound_duration1 + "s");
	sys.wait(sound_duration1);

float	sound_duration2 = $player1.startSoundShader("elevator03_loop", SND_CHANNEL_ANY);
	sys.println("sound duration2 is " + sound_duration2 + "s");
	sys.wait(sound_duration2);
	$player1.stopSound(SND_CHANNEL_ANY, 0);

float	sound_duration3 = $player1.startSoundShader("elevator03_end", SND_CHANNEL_ANY);
	sys.println("sound duration3 is " + sound_duration3 + "s");
	sys.wait(sound_duration3);
}


void main()
{
	sys.waitFrame();
//	thread test_startSound();		//doesn't work
	thread test_startSoundShader();		//works
}

 

Now I'm no longer sure if I ever managed to get startSound to play a sound. Been experimenting with netSync 0/1 as well as alternative channels. You can specify a channel either with text or a number: tried channel 0, 1, 5, 9, 11, SND_CHANNEL_UNUSED, _UNUSED_2 and _ANY, I never hear anything and duration is 0.

Share this post


Link to post
Share on other sites

This startSound, you must pass name of spawnarg in the entity which you call it on. The name must also start with snd_, because for any such spawnarg the engine preloads sound file on map load. You cannot pass name of sound shader directly. By the way, a good approach to see how a function actually works is to find its usages in the core scripts, e.g.:

    if ( vine.getKey( "snd_grow" ) != "" )
        vine.startSound( "snd_grow", SND_CHANNEL_BODY, false );

 

The serious downside of startSound is that you cannot play a sound on entity B if you have it in a spawnarg of entity A. Which seems to be your case.

I guess it won't a problem if you use startSoundShader on a sound shader which is specified as snd_open or snd_close in some already spawned entity. It should be preloaded anyway, and already available at the moment when you use it. But in general, if you use startSoundShader, then you should do cacheSoundShader before that, preferably during initialization.

  • Thanks 1

Share this post


Link to post
Share on other sites

Ah, that clears up why I was having such a rough/inconsistent experience with scripting sounds. Turns out I've been missing theory.

So, I've switched to startSound for snd_open without problems now. Will still keep startSoundShader for snd_close because I want to run that on a different entity which may have a different/missing snd_close spawnarg, but added a line to cache snd_close in initialisation.

Also fixed a bug: turns out I can't check multiple conditionals side by side in the same for(), so the teledoor was missing some target assignments. Moved them into each their own for() and they catch everything now. Broken & working versions:

Spoiler

for(...)
	{
		target = getTarget(i);
		if(target.getKey("classname") == "info_player_teleport")
			{works}

		else if(target.getKey("classname") == "atdm:teledoor")
			{doesn't occur}
	}

 

Spoiler

for(...)
	{
		target = getTarget(i);
		if(target.getKey("classname") == "info_player_teleport")
			{works}
	}

for(...)
	{
		target = getTarget(i);
		if(target.getKey("classname") == "atdm:teledoor")
			{works}
	}

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...