Results 1 to 8 of 8

Thread: Spawnable Triggers

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Brigadier General
    Join Date
    Oct 2012
    Posts
    994
    Thanks
    20
    Thanked 588 Times in 388 Posts
    Quote Originally Posted by kung foo man View Post
    Well, normal spawnable triggers are spheres only and this is box + debug lines, which are kinda helpful.
    But it's the efficiency of the code that is questionable. It can all be done so much simpler and just as effectively, without putting such a strain on the server. This is my universal trigger function for COD1, which doesn't natively support triggers which can be delimited by radius (there is no trigger_radius in COD1 - only trigger_multiple can be spawned dynamically):

    Code:
    spawnTrigger( origin, radius )
    {
    	ent = spawn( "script_origin", origin );
    	ent.origin = origin;
    	ent.touchingPlayer = [];
    	ent.touchingRadius = radius;
    	ent thread flag_touching();
    	
    	return( ent );
    }
    
    flag_touching()
    {
    	level endon( "intermission" );
    	
    	/#
    	showBoundedArea( self, (1,0,0) );
    	#/
    
    	for( ;; )
    	{
    		players = getEntArray( "player", "classname" );
    			
    		for( i=0; i < players.size; i++ )
    		{
    			player = players[i];
    			
    			if( isPlayer( player ) && isAlive( player ) && player.sessionstate == "playing" )
    			{	
    				if( distance( self.origin, player.origin ) < self.touchingRadius )
    				{
    					self notify( "trigger", player );
    				}
    			}
    		}
    		
    		wait( 0.05 );
    	}
    }
    
    
    showBoundedArea( trigger, color )
    {
    	player_height = 80.0;
    	center = trigger.origin;
    	forward = anglestoforward( trigger.angles );
    	right = anglestoright( trigger.angles );
    
    	forward = maps\mp\_utility::vectorScale( forward, trigger.touchingRadius );
    	right = maps\mp\_utility::vectorScale( right, trigger.touchingRadius );
    
    	a = center + forward - right;
    	b = center + forward + right;
    	c = center - forward + right;
    	d = center - forward - right;
    	
    	thread lineUntilNotified( a, b, color, 0 );
    	thread lineUntilNotified( b, c, color, 0 );
    	thread lineUntilNotified( c, d, color, 0 );
    	thread lineUntilNotified( d, a, color, 0 );
    
    	thread lineUntilNotified( a, a + (0, 0, player_height), color, 0 );
    	thread lineUntilNotified( b, b + (0, 0, player_height), color, 0 );
    	thread lineUntilNotified( c, c + (0, 0, player_height), color, 0 );
    	thread lineUntilNotified( d, d + (0, 0, player_height), color, 0 );
    
    	a = a + ( 0, 0, player_height );
    	b = b + ( 0, 0, player_height );
    	c = c + ( 0, 0, player_height );
    	d = d + ( 0, 0, player_height );
    	
    	thread lineUntilNotified( a, b, color, 0 );
    	thread lineUntilNotified( b, c, color, 0 );
    	thread lineUntilNotified( c, d, color, 0 );
    	thread lineUntilNotified( d, a, color, 0 );
    	
    }
    
    lineUntilNotified( start, end, color, depthTest )
    {	
    	for( ;; )
    	{
    		line( start, end, color, depthTest );
    		wait( 0.05 );
    	}
    }
    And the developer mode produces this marked bounded area:



    In the gametype files, you code it as if it were a trigger_radius. This is my trigger think for CTF for COD1:

    Code:
    flag_think()
    {
    	level endon( "intermission" );
    	
    	objective_add( self.objective, "current", self.origin, self.compassflag );
    
    	for( ;; )
    	{
    		self waittill( "trigger", player );
    			
    		if( isPlayer( player ) && isAlive( player ) && player.sessionstate == "playing" )
    		{	
    			// PICKUP THE FLAG !!
    			if( player.pers["team"] != self.team )
    			{
    				if( self.atbase )
    				{
    					if( player.pers["team"] == "allies" )
    						player AnnouncetoAll( &"CTF_STOLE_AXIS", player.name );
    					else
    						player AnnouncetoAll( &"CTF_STOLE_ALLIES", player.name );
    					
    					thread logEvent( "ctf_pickedup_flag", player );
    				}
    				else
    				{
    					if( player.pers["team"] == "allies" )
    						player AnnouncetoAll( &"CTF_TAKEN_BACK_AXIS", player.name );
    					else
    						player AnnouncetoAll( &"CTF_TAKEN_BACK_ALLIES", player.name );
    						
    					thread logEvent( "ctf_pickedup_dropped_flag", player );
    				}
    				
    				player pickupFlag( self );
    
    				friendlyAlias = "ctf_touchenemy";
    				enemyAlias = "ctf_enemy_touchenemy";
    				
    				thread [[level.onPlaySoundOnPlayers]]( friendlyAlias, self.team );
    				thread [[level.onPlaySoundOnPlayers]]( enemyAlias, [[level.getOtherTeam]]( self.team ) );
    							
    				thread [[level.onPlaySoundOnPlayers]]( game["flagTaken"][ player.pers["team"] ], player.pers["team"] );
    
    			}
    			else 
    			{
    				// CAPTURED THE FLAG !!
    				if( self.atbase )
    				{
    					if( isdefined( player.flag ) )
    					{
    						player.flag returnFlag( undefined );
    						player detachFlag( player.flag );
    						player.flag = undefined;
    						player.statusicon = "";
    
    						player.score += 10;
    						teamscore = getTeamScore( player.pers["team"] );
    						teamscore += 1;
    						setTeamScore( player.pers["team"], teamscore );
    						level notify( "update_allhud_score");
    	
    						if( player.pers["team"] == "allies" )
    							self AnnouncetoAll( &"CTF_CAPTURED_AXIS", player.name );
    						else
    							self AnnouncetoAll( &"CTF_CAPTURED_ALLIES", player.name );	
    
    						friendlyAlias = "ctf_touchcapture";
    						enemyAlias = "ctf_enemy_touchcapture";
    
    						thread [[level.onPlaySoundOnPlayers]]( game["flagCapped"][ [[level.getOtherTeam]]( player.pers["team"] ) ] );
    
    						thread [[level.onPlaySoundOnPlayers]]( friendlyAlias, player.pers["team"] );
    						thread [[level.onPlaySoundOnPlayers]]( enemyAlias, [[level.getOtherTeam]]( player.pers["team"] ) );
    						
    						thread logEvent( "ctf_captured_flag", player );
    
    						maps\mp\gametypes\_globallogic::checkScoreLimit();
    					}
    				}
    				else // RETURNED FLAG TO BASE !!
    				{							
    					self returnFlag( true );
    
    					if( self.team == "allies" )
    						self AnnouncetoAll( &"CTF_RETURNED_ALLIES", player.name );
    					else
    						self AnnouncetoAll( &"CTF_RETURNED_AXIS", player.name );
    						
    					thread [[level.onPlaySoundOnPlayers]]( "ctf_touchown", player.pers["team"] );
    						
    					thread logEvent( "ctf_returned_own_flag", player );
    					
    					player.score += 2;
    					level notify( "update_allhud_score" );
    				}
    			}
    		}
    		
    		wait( 0.05 );
    	}
    }
    Ockham's Razor: All things being equal, the SIMPLEST solution is the right one. And my method - the method used by modders before trigger_radius was introduced in COD2 - is to use a distance test of a script_origin against all players. Such a method is less server CPU heavy than SniperFire's method.
    Last edited by Tally; 5th December 2014 at 07:27.

  2. #2
    Assadministrator IzNoGoD's Avatar
    Join Date
    Aug 2012
    Posts
    1,718
    Thanks
    17
    Thanked 1,068 Times in 674 Posts
    1. You are using an implementation that emulates a trigger_radius, yet your screenshot shows a cube-like area, shouldnt it be a spherical area?
    2. Why not use distancesquared instead, this saves you a squareroot operation per frame per player, and squareroot operations are VERY expensive
    "Does not work" is an error report for a bug between keyboard and chair.

    All hail Artie Effem

  3. #3
    Brigadier General
    Join Date
    Oct 2012
    Posts
    994
    Thanks
    20
    Thanked 588 Times in 388 Posts
    Quote Originally Posted by IzNoGoD View Post
    1. You are using an implementation that emulates a trigger_radius, yet your screenshot shows a cube-like area, shouldnt it be a spherical area?
    2. Why not use distancesquared instead, this saves you a squareroot operation per frame per player, and squareroot operations are VERY expensive
    1. As you rightly say, I am EMULATING a trigger radius. Hence it can be square, rectangle, oblong, or bannana shaped, it doesn't matter. As long as the functionality is the same, it doesn't matter what shape it is.

    2. distanceSquared is not a built-in function in COD1, and I didn't emulate it or distance2d() (which I actually have in my utility files) because you actually need the height check in CTF as you move the trigger below the trigger radius in order to stop it triggering (cf. maps\mp\_utility::triggerOff()).

    For the record, and so I don't have to keep saying it, this is a list of things which AREN'T in COD1:

    no file functions. You cannot write to a file in any manner other than a log file. The only file formats you can read from are .GSC and .CFG;
    no including files (i.e. #include <directory><filename>), you have to either manually thread to them, or build function pointers;
    no trigger_radius;
    no isSubStr();
    no getSubStr();
    no strTok();
    no openscriptmenu command;
    no updated menu language at all, just pure Quake 3 functions and syntax;
    no closeingamemenu();
    no playerADS();
    only 2 channels for sound, so when you have 2 sounds playing simultaneously, if you play a 3rd, the sound of 1 of the others cuts out (the Quake 3 Team Arena engine natively has only 1 sound thread. It took other companies to implement sound functions such as 5.1 and EAX)
    no getTagOrigin();
    you cannot color light in COD1. It is just yellow, and the only way to color it is pass yellow light through a colored shader. In the COD2 engine, you can manipulate light directly, using 6 different parameters.
    no physicstrace();
    no fragbuttonpressed();
    no GetOffhandSecondaryClass() (because grenades go into their own weapon slots - the slots are "primary", "primaryb", "pistol", "grenade", "smokegrenade". You can put a grenade in the pistol slot and it will work, and vice versa, as long as you change the slot name);
    no "cg_fovscale" dvar;
    no "cg_fovmin" dvar (so you can't zoom in with a sniper scope like you can in COD2/COD4);
    no getPlayerAngles();

    That list is by no means exhaustive. It is just the things I have come across while building my current mod for COD1. the engine is seriously limited. I have reproduced the basic functions we all take for granted because I needed them, but there are things I want but can't have because they have to be built into the engine. Here are some of the basics I have built:

    Code:
    strTok( string, token )
    {
    	j = 0;
    	temparr[j] = "";	
    
    	for( i = 0; i < string.size; i++ )
    	{
    		if( string[i] == token )
    		{
    			j++;
    			temparr[j] = "";
    		}
    		else
    			temparr[j] += string[i];
    	}
    	
    	return( temparr );
    }
    
    getSubStr( string, start, end )
    {
    	temp = "";
    	count = 0;
    	if( start > 0 )
    	{
    		for( i=start; i < string.size; i++ )
    		{	
    			if( isDefined( end ) && count >= end )
    				break;
    
    			temp = temp + string[i];
    			count++;
    		}
    	}
    	else
    	{
    		for( i=0; i < string.size; i++ )
    		{
    			if( isDefined( end ) && i >= end )
    				break;
    				
    			temp = temp + string[i];
    		}
    	}
    	
    	return( temp );
    }
    
    isSubStr( str1, str2 )
    {
    	// compare string1 with string2
    	for( i=0; i < str2.size - str1.size; i++ )
    	{
    		temp = "";
    		for( j=0; j < str1.size; j++ )
    		{
    			temp = temp + str2[ i + j ];
    		}
    
    	   if( str1 == temp )
    		  return( true );
    	}
    
    	// if 1st comparision fails compare string2 with string1
    	for( i=0; i < str1.size - str2.size; i++ )
    	{
    		temp = "";
    		for( j=0; j < str2.size; j++ )
    		{
    			temp = temp + str1[ i + j ];
    		}
    
    	   if( str2 == temp )
    		  return( true );
    	}
    	
    	// all comparisons failed
    	return( false );
    }
    
    distance2d( a, b )
    {
    	return( distance( (a[0],a[1],0), (b[0],b[1],0) ) );
    }
    Last edited by Tally; 5th December 2014 at 09:17.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •