kung foo man
11th October 2013, 11:11
Just found this old function, don't remember where I initially found it:
orientToNormal( normal )
{
    hor_normal = ( normal[ 0 ], normal[ 1 ], 0 );
    hor_length = length( hor_normal );
    if ( !hor_length )
        return( 0, 0, 0 );
    hor_dir = vectornormalize( hor_normal );
    neg_height = normal[ 2 ] * - 1;
    tangent = ( hor_dir[ 0 ] * neg_height, hor_dir[ 1 ] * neg_height, hor_length );
    plant_angle = vectortoangles( tangent );
    //println("^6hor_normal is ", hor_normal);
    //println("^6hor_length is ", hor_length);
    //println("^6hor_dir is ", hor_dir);
    //println("^6neg_height is ", neg_height);
    //println("^6tangent is ", tangent);
    //println("^6plant_angle is ", plant_angle);
    return plant_angle;
}
Dunno which yaw angle it computes though
serthy
15th October 2013, 18:51
480
i call it TANKTRESS ... :cool:
call on map start before any wait statements:
init()
{
	level.killtube = true;
	if( level.killtube )
	{
		level.model_body[0] = "xmodel/furniture_bedmattress1";
		level.model_tower[0] = "xmodel/prop_barrel_benzin";
		level.model_gun[0] = "xmodel/weapon_30cal";
		level.model_track[0] = "xmodel/tag_origin";
		level.model_track_scroll[0] = "xmodel/tag_origin";
	}
	else
	{
		level.model_body[0] = "xmodel/serthy_tank_a_body";
		level.model_tower[0] = "xmodel/serthy_tank_a_tower";
		level.model_gun[0] = "xmodel/serthy_tank_a_gun";
		level.model_track[0] = "xmodel/serthy_tank_a_track";
		level.model_track_scroll[0] = "xmodel/serthy_tank_a_track_scroll";
	}
	precacheModel( level.model_body[0] );
	precacheModel( level.model_tower[0] );
	precacheModel( level.model_gun[0] );
	precacheModel( level.model_track[0] );
	precacheModel( level.model_track_scroll[0] );
	if( level.killtube )
	{
		level.model_body[1] = "xmodel/furniture_bedmattress1";
		level.model_tower[1] = "xmodel/prop_barrel_benzin";
		level.model_gun[1] = "xmodel/weapon_30cal";
		level.model_track[1] = "xmodel/tag_origin";
		level.model_track_scroll[1] = "xmodel/tag_origin";
	}
	else
	{
		level.model_body[1] = "xmodel/serthy_tank_b_body";
		level.model_tower[1] = "xmodel/serthy_tank_b_tower";
		level.model_gun[1] = "xmodel/serthy_tank_b_gun";
		level.model_track[1] = "xmodel/serthy_tank_b_track";
		level.model_track_scroll[1] = "xmodel/serthy_tank_b_track_scroll";
	}
	precacheModel( level.model_body[1] );
	precacheModel( level.model_tower[1] );
	precacheModel( level.model_gun[1] );
	precacheModel( level.model_track[1] );
	precacheModel( level.model_track_scroll[1] );
	spawns = getEntArray( "mp_tdm_spawn" , "classname" );
	for( i = 0 ; isDefined( spawns ) && i < spawns.size && i < 15 ; i++ )
	{
		level thread spawnTank( spawns[i].origin );
	}
}
spawnTank( pos )
{
	wait( 1.0 );
	tank = spawn( "script_model" , pos + ( 0 , 0 , 0 ) );
	tank.body = spawn( "script_model" , pos + ( 0 , 0 , 0 ) );
	tank.tower = spawn( "script_model" , pos + ( 0 , 0 , 0 ) );
	tank.gun = spawn( "script_model" , pos + ( 60 , 0 , 80 ) );
	if( level.killtube )
		tank.gun.origin = pos + ( 10 , 0 , 30 );
	tank.typeID = randomInt( 2 );
	tank setModel( level.model_track[tank.typeID] );
	tank.body setModel( level.model_body[tank.typeID] );
	tank.tower setModel( level.model_tower[tank.typeID] );
	tank.gun setModel( level.model_gun[tank.typeID] );
	tank.gun linkTo( tank.tower );
	
	tank.vehicleType = "tank";
	tank.targetname = "vehicle";
	tank.speed = 0;
	tank.maxSpeed = 30;
	tank.minSpeed = -10;
	tank.gear = 1;
	tank.maxHealth = 200;
	tank.health = tank.maxHealth;
	tank.anglesF = anglesToForward( tank.angles );
	tank.anglesR = anglesToRight( tank.angles );
	tank.anglesU = anglesToUp( tank.angles );
	tank thread tankTriggerLogic();
	tank thread tankLogic();
}
tankTriggerLogic()
{
	trigger = spawn( "trigger_radius" , self.origin , 0 , 200 , 200 );
	trigger enableLinkTo();
	trigger linkTo( self );
	self.trigger = trigger;
	
	trigger endon( "death" );
	while( isDefined( self ) )
	{
		trigger waittill( "trigger" , player );
		if( !isDefined( player ) || !isPlayer( player ) || !isAlive( player ) || !player useButtonPressed() )
			continue;
		else if( isDefined( player.vehicle ) || isDefined( self.driver ) || isDefined( player.isBot ) )
			continue;
		self thread attachPlayer( player );
	}
	trigger unLink();
	trigger notify( "death" );
	wait( 0.05 );
	if( isDefined( trigger ) )
		trigger delete();
}
monitorPlayer()
{
	self endon( "disconenct" );
	self endon( "exitVehicle" );
	self waittill( "killed_player" );
	assert( isDefined( self.vehicle ) );
	self.vehicle detachPlayer( self );
}
attachPlayer( player )
{
	player endon( "disconenct" );
	player endon( "killed_player" );
	if( !isDefined( self.driver ) )
	{
		self.driver = player;
		player setOrigin( self.origin + ( 0 , 0 , 70 ) );
		player linkTo( self );
		player disableWeapon();
		player.vehicle = self;
		player hide();
		player setModel( "" );
		player setClientCvar( "cg_thirdperson" , 1 );
		player setClientCvar( "cg_thirdpersonrange" , 200 );
		player setClientCvar( "cg_thirdpersonangle" , 0 );
		player thread monitorPlayer();
	}
	else
	{
		return iPrintLn( "Tank tried to attach player as driver while having a driver!" );
	}
}
detachPlayer( player )
{
	player endon( "disconenct" );
	wait( 0.05 );
	player unlink();
	player enableWeapon();
	player setClientCvar( "cg_thirdperson" , 0 );
	//if( isDefined( player.pers["savedmodel"] ) );
	//	player loadModel( player.pers["savedmodel"] );
	player.vehicle = undefined;
	self.driver = undefined;
	player notify( "exitVehicle" );
}
checkCollission( trace )
{
	if( trace["fraction"] == 1 )
		return false;
	if( isDefined( trace["entity"] ) )
	{
		if( isPlayer( trace["entity"] ) )
			trace["entity"] suicide();
		return false;
	}
	return true;
}
vectorScale( v , s )
{
	return ( v[0] * s , v[1] * s , v[2] * s );
}
tankLogic()
{
	self endon( "death" );
	self endon( "destroyed" );
	speedTreshold = 3;
	timeStep = 0.1;
	for( i = 0 ; true ; i++ )
	{
		wait( timeStep / 2 );
		self.anglesF = anglesToForward( self.angles );
		self.anglesR = anglesToRight( self.angles );
		self.anglesU = anglesToUp( self.angles );
		self.nextAngles = self.angles;
		buttonMelee = false;
		buttonAttack = false;
		buttonUse = false;
		pitch = undefined;
		desiredDir = self.angles;
		if( !isDefined( self.driver ) )
		{
			if( self.speed != 0 )
			{
				if( self.speed > 0 )
					self.speed -= 1;
				else
					self.speed += 1;
			}
		}
		else
		{
			buttonMelee = self.driver meleeButtonPressed();
			buttonAttack = self.driver attackButtonPressed();
			buttonUse = self.driver useButtonPressed();
			if( buttonMelee )
			{
				if( buttonUse )
				{
					if( self.speed > 0 )
					{
						self.speed -= 6;
						if( self.speed < 0 )
							self.speed = 0;
					}
					else
						self.speed -= 1;
				}
				else
				{
					self.speed += 2;
				}
			}
			else
			{
				if( self.speed * self.gear < speedTreshold )
					self.speed = 0;
				else
					self.speed -= ( self.gear * 1 );
			}
		}
		if( self.speed > self.maxSpeed )
			self.speed = self.maxSpeed;
		else if( self.speed < self.minSpeed )
			self.speed = self.minSpeed;
		self.gear = 1;
		if( self.speed < 0 )
			self.gear = -1;
		if( ( self.speed * self.gear >= speedTreshold ) || buttonAttack && i % 2 == 0 )
		{
			s = vectorScale( self.anglesR , 60 );
			f = vectorScale( self.anglesF , 100 + self.speed );
			b = vectorScale( self.anglesF , -70 );
			h = ( 0 , 0 , 164 );
			flt = bulletTrace( self.origin + f - s + h , self.origin + f - s - h , false , self );
			frt = bulletTrace( self.origin + f + s + h , self.origin + f + s - h , false , self );
			bt = bulletTrace( self.origin + b + h , self.origin + b - h , false , self );
			diff = frt["position"] - flt["position"];
			nextPos = flt["position"] + vectorScale( diff , 0.5 ) - vectorScale( self.anglesF , 100 );
			playerDir = self.driver getPlayerAngles();
			if( buttonAttack )
				desiredDir = playerDir;
			yaw = desiredDir[1] - self.angles[1];
			while( yaw < -180 )
				yaw += 360;
			while( yaw > 180 )
				yaw -= 360;
			pitch = vectorToAngles( flt["position"] + vectorScale( diff , 0.5 ) - bt["position"] );
			yaw = self.angles[1] + ( yaw * 15 / 180 );
			roll = vectorToAngles( diff );
			if( ( self.speed * self.gear >= speedTreshold ) || buttonAttack )
			{
				self.nextAngles = ( pitch[0] , yaw , roll[0] );
	
				self rotateTo( self.nextAngles , timeStep , 0 , 0 );
				self.body rotateTo( self.nextAngles , timeStep , 0 , 0 );
			
				self moveTo( nextPos + ( 0 , 0 , 1 ) , timeStep , 0 , 0 );
				self.tower moveTo( nextPos + ( 0 , 0 , 1 ) , timeStep , 0 , 0 );
				self.body moveTo( nextPos + ( 0 , 0 , 1 ) , timeStep , 0 , 0 );
			
				if( self.model != level.model_track_scroll[self.typeID] )
					self setModel( level.model_track_scroll[self.typeID] );
			}
		}
		else
		{
			if( self.model != level.model_track[self.typeID] )
				self setModel( level.model_track[self.typeID] );
		}
		if( isDefined( self.driver ) )
		{
			pa = self.driver getPlayerAngles();
			pu = anglesToUp( pa );
			pr = anglesToRight( pa );
			pf = anglesToForward( pa );
			ta = self.nextAngles;
			tu = anglesToUp( ta );
			tr = anglesToRight( ta );
			tf = anglesToForward( ta );
			sa = self.tower.angles;
			su = anglesToUp( sa );
			sr = anglesToRight( sa );
			sf = anglesToForward( sa );
		
			//project playerdir onto tanks xy plane
			//a = vectorToAngles( pf - vectorScale( tu , vectorDot( tu , pf ) ) );
			d = vectorDot( tu , pf );
			a = sf;
			if( d < 0.98 && d > -0.98 )
				a = vectorNormalize( pf - vectorScale( tu , d ) );
			dbgHeight = 64;
			dbgLength = 60;
			if( level.killtube )
			{
				dbgHeight = 0;
				dbgLength = 30;
			}
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( a , dbgLength ) , ( 1 , 0 , 1 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( pf , dbgLength ) , ( 1 , 1 , 0 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( tu , dbgLength ) , ( 0 , 1 , 0 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( tf , dbgLength ) , ( 0 , 1 , 0 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( tr , dbgLength ) , ( 0 , 1 , 0 ) );
			//line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( tf , 0 - dbgLength ) , ( 0 , 1 , 0 ) );
			//line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( tr , 0 - dbgLength ) , ( 0 , 1 , 0 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( su , dbgLength ) , ( 0 , 0 , 1 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( sf , dbgLength ) , ( 0 , 0 , 1 ) );
			line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( sr , dbgLength ) , ( 0 , 0 , 1 ) );
			//line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( sf , 0 - dbgLength ) , ( 0 , 0 , 1 ) );
			//line( self.origin + ( 0 , 0 , dbgHeight ) , self.origin + ( 0 , 0 , dbgHeight ) + vectorScale( sr , 0 - dbgLength ) , ( 0 , 0 , 1 ) );
			r = sa[2];
			if( vectorDot( tu , su ) < 0.999 )
			{
				r = vectorToAngles( vectorNormalize( tu - su ) );
				r = r[0];
			}
			while( r < -180 )
				r += 360;
			while( r > 180 )
				r -= 360;
			a = vectorToAngles( a );
			a = ( a[0] , a[1] , r );
			if( i % 2 == 0 )
				self.tower rotateTo( a , timeStep , 0 , 0 );
		}
	}
}
sign( x )
{
	if( x < 0 )
		return -1;
	return 1;
}
vectorcross(a,b)
{
	return ( a[1] * b[2] - b[1] * a[2] , a[2] * b[0] - b[2] * a[0] , a[0] * b[1] - b[0] * a[1] );
}
sqrt( x )
{
	y = x;
	for( z = x / 4 ; abs( z - y ) >= 0.001 ; y = ( ( z + ( x / z ) ) / 2 ) )
	{
		z = y;
	}
	return y;
}
abs( x )
{
	if( x < 0 )
		x = 0 - x;
	return x;
}
aTan2( y,x) {
	 coeff_1 = 3.14159265359 / 4;
	 coeff_2 = 3 * coeff_1;
	 abs_y = abs(y);
	if (x >= 0 ) {
		r = (x - abs_y) / (x + abs_y);
		angle = coeff_1 - coeff_1 * r;
	} else {
		r = (x + abs_y) / (abs_y - x);
		angle = coeff_2 - coeff_1 * r;
	}
	if(y < 0)
		angle *= -1;
	return angle;
}
Hold [F] for to drive
Hold [F + Melee] to break/ drive backwards
Hold [Attack] to align the Tanktress to the current direction
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.