Hell's Cube - Rotating Imps

/******************************************/
/*********** PUZZLE 4 - START *************/
/******************************************/

void activatePuzzle4SpawnAndRotateImp(float nSpawnIndex, float nImpIndex)
{
	 while(1)
	 {
		entity platform;
		entity point1;
		entity point2;
			
		platform = sys.getEntity("puzzle4_rotating_platform_"+nSpawnIndex);
		point1	= sys.getEntity("puzzle4_point_"+((2*nSpawnIndex) -1));
		point2	= sys.getEntity("puzzle4_point_"+(2*nSpawnIndex));
			
		vector center;
		vector p1;
		vector p2;
		vector v1;
		vector v2;
		vector cross;
		vector normal;
	 	 
		float mag;
	 	 
		center	= platform.getWorldOrigin();
			
		p1	= point1.getWorldOrigin();
		p2	= point2.getWorldOrigin();
	 	 
		v1_x	= p1_x - center_x;
		v1_y	= p1_y - center_y;
		v1_z	= p1_z - center_z;
	 	 
		v2_x	= p2_x - center_x;
		v2_y	= p2_y - center_y;
		v2_z	= p2_z - center_z;
	 	 
		cross	= sys.CrossProduct(v2,v1);
	 	 
		mag	= (sys.sqrt((v1_x*v1_x) + (v1_y*v1_y) + (v1_z*v1_z)))* (sys.sqrt((v2_x*v2_x) + (v2_y*v2_y) + (v2_z*v2_z)));
	 	
		normal_x	= cross_x/mag;
		normal_y	= cross_y/mag;
		normal_z	= cross_z/mag;
	 	 
		//sys.waitFrame();
	 	 
		vector impOrigin;	 
	 	 
		entity imp;
		entity imp2;
	 	 
	 	float nOffset = 0;
	 		
		imp	= sys.getEntity("puzzle4_imp_"+nImpIndex); 
		imp2	= sys.getEntity("puzzle4_imp_"+(nImpIndex + 1));
	 		
		if (imp == $null_entity)
		{	
			impOrigin = imp2.getWorldOrigin();
	 	 
			sys.setSpawnArg("origin",vectorToString(impOrigin));
			sys.setSpawnArg("name","puzzle4_imp_"+nImpIndex);
				 
			nOffset = 0;
		}
		else
		{	
			imp2 = imp;
	 			
			impOrigin = imp2.getWorldOrigin();
	 	 
			sys.setSpawnArg("origin",vectorToString(impOrigin));
			sys.setSpawnArg("name","puzzle4_imp_"+(nImpIndex + 1));
				 
			nOffset = 1;
		}
	 	 
		sys.setSpawnArg("anim","idle");
		sys.setSpawnArg("no_sight","1");
		sys.setSpawnArg("angle","180");
		sys.setSpawnArg("noDamage","1");
		sys.setSpawnArg("bind","puzzle4_rotating_platform_"+nSpawnIndex);
		sys.setSpawnArg("gravityDir",vectorToString(normal));
	 		
		imp = sys.spawn("monster_demon_imp_crawler");

		imp.bind(platform);
		imp.playAnim(1,"idle");
		imp.playAnim(2,"idle");

		sys.wait(.025);
	 		
		imp2.remove();
	 	 	
		sys.wait(.025);
	}
}

void startPuzzle4SpawnHellknight()
{
	 entity hellknight;
	 
	 hellknight = sys.getEntity("puzzle4_hellknight");
	 
	 if (hellknight == $null_entity && g_nNumPuzzle4ImpsSpawned >= g_nCountPuzzle4ForHellknightSpawn)
	 {
		sys.setSpawnArg("origin",$puzzle4_hellknight_spawn.getWorldOrigin());
		sys.setSpawnArg("name","puzzle4_hellknight");
		sys.setSpawnArg("hide","2");
		sys.setSpawnArg("health","20");
		sys.setSpawnArg("teleport","1");
			
		hellknight = sys.spawn("monster_demon_hellknight");
			
		sys.trigger(hellknight);		
	 }
		
	 sys.killthread("startPuzzle4SpawnHellknight");
}

void activatePuzzle4RotatePlatform(float nSpawnIndex, float nImpIndex)
{
	 entity imp;
	 entity imp2;
	 entity impSpawn;
	 entity platform;

	 vector impOrigin;
	  			
	 imp	= sys.getEntity("puzzle4_imp_"+nImpIndex);
	 imp2	= sys.getEntity("puzzle4_imp_"+(nImpIndex + 1));
	 impSpawn = sys.getEntity("puzzle4_imp_spawn_"+nSpawnIndex);
	 platform = sys.getEntity("puzzle4_rotating_platform_"+nSpawnIndex);
	 
	 // initially spawn a imp if you need to and let him rest on the platform
	 
	 if (imp == $null_entity && imp2 == $null_entity)
	 {
		impOrigin = impSpawn.getWorldOrigin();
	 	 
		sys.setSpawnArg("origin",vectorToString(impOrigin));
		sys.setSpawnArg("name","puzzle4_imp_"+nImpIndex);
		sys.setSpawnArg("anim","idle");
		sys.setSpawnArg("no_sight","1");
		sys.setSpawnArg("angle","180");
		sys.setSpawnArg("noDamage","1");
		sys.setSpawnArg("gravityDir","0 0 1");
	 		
		imp = sys.spawn("monster_demon_imp_crawler");
			
	 	sys.wait(1);
	 		
		imp.bind(platform);	
	 }
				 
	 // Rotate imp
	 
	 thread activatePuzzle4SpawnAndRotateImp(nSpawnIndex,nImpIndex);
	 
	 // Rotate platform
	 
	 platform.rotateOnce('0 0 180');
	 
	 sys.waitFor(platform);
	 
	 sys.killthread("activatePuzzle4SpawnAndRotateImp");
	 
	 // Clean up if imps were improperly spawned, and respawn just one imp
	 
	 imp	= sys.getEntity("puzzle4_imp_"+nImpIndex);
	 imp2	= sys.getEntity("puzzle4_imp_"+(nImpIndex + 1));
	 
	 entity releasePoint;

	 if (imp != $null_entity)
	 {	 		
		releasePoint = sys.getEntity("puzzle4_imp_release_"+nSpawnIndex);
			
		impOrigin = releasePoint.getWorldOrigin();

		imp.remove();

		sys.wait(0.025);
			
		sys.setSpawnArg("origin",vectorToString(impOrigin));
		sys.setSpawnArg("name","puzzle4_imp_"+nImpIndex);  
		sys.setSpawnArg("angle","180");
		sys.setSpawnArg("health","10");
			
		imp = sys.spawn("monster_demon_imp_crawler");

		$puzzle4_imp_count.setKey("imp_"+nImpIndex,"1");
	 	$puzzle4_imp_wasAlive.setKey("imp_"+nImpIndex,"1");
	 		
	 	imp.activate(imp);
	 		
	 	if (imp2 != $null_entity)
	 	{
	 		$puzzle4_imp_count.setKey("imp_"+(nImpIndex - 1),"0");
	 		$puzzle4_imp_wasAlive.setKey("imp_"+(nImpIndex - 1),"0");
	 		
	 		imp2.remove();
	 	}
	 		
	 	if (g_nNumPuzzle4ImpsSpawned >= g_nCountPuzzle4ForHellknightSpawn)
	 	{
	 		g_nNumPuzzle4ImpsSpawned = 0;
	 	}
	 	g_nNumPuzzle4ImpsSpawned++;
	 		
	 	thread startPuzzle4SpawnHellknight();
	 }
	 
	 if (imp2 != $null_entity)
	 { 		
		releasePoint = sys.getEntity("puzzle4_imp_release_"+nSpawnIndex);
			
		impOrigin = releasePoint.getWorldOrigin();
			
		imp2.remove();
			
		sys.wait(0.025);
			
		sys.setSpawnArg("origin",vectorToString(impOrigin));
		sys.setSpawnArg("name","puzzle4_imp_"+(nImpIndex - 1));  
		sys.setSpawnArg("angle","180");
		sys.setSpawnArg("health","10");
			
		imp2 = sys.spawn("monster_demon_imp_crawler");
			
		$puzzle4_imp_count.setKey("imp_"+(nImpIndex - 1),"1");
	 	$puzzle4_imp_wasAlive.setKey("imp_"+(nImpIndex - 1),"1");
	 		
	 	imp2.activate(imp);
	 		
	 	if (imp != $null_entity)
	 	{
	 		$puzzle4_imp_count.setKey("imp_"+nImpIndex,"0");
	 		$puzzle4_imp_wasAlive.setKey("imp_"+nImpIndex,"0");
	 		
	 		imp.remove();
	 	}
	 		
	 	if (g_nNumPuzzle4ImpsSpawned >= g_nCountPuzzle4ForHellknightSpawn)
	 	{
	 		g_nNumPuzzle4ImpsSpawned = 0;
	 	}
	 		
	 	g_nNumPuzzle4ImpsSpawned++;
	 		
	 	thread startPuzzle4SpawnHellknight();
	 }	 
	 
	 entity barrier;
	 
	 vector barrierPosition;
	
	 barrier = sys.getEntity("puzzle4_blocking_volume_"+nSpawnIndex);
	 					 
	 barrierPosition = barrier.getWorldOrigin();
							 
	 barrierPosition_z -= 64.0;
							 
	 barrier.setWorldOrigin(barrierPosition);
	 
	 sys.killthread("activatePuzzle4RotatePlatform");
}

void startPuzzle4RotatingAndSpawn()
{
	 while(!g_bHasPuzzle4Ended)
	 {
		// Check if any of the Puzzle 4 Imps have died

		float	i;
		float	nCount;
			
		entity	 imp;

		boolean	 bDecrementImpCount;
			
		nCount	= 2;
			
		bDecrementImpCount = _FALSE;
			
		for (i = 1; i <= 2*g_nNumPuzzle4MaxImps; i++)
		{				 
			nCount--;
				 
			 imp = sys.getEntity("puzzle4_imp_"+i);
				 
			if (imp == $null_entity &&
				g_nNumPuzzle4Imps > 0 &&
				$puzzle4_imp_wasAlive.getIntKey("imp_"+i) == 1)
			{	
				$puzzle4_imp_count.setKey("imp_"+i,"0");
				$puzzle4_imp_wasAlive.setKey("imp_"+1,"0");

				bDecrementImpCount = _TRUE;
			}
				 
			 if (nCount == 0)
			{
				if (bDecrementImpCount)
				{
					bDecrementImpCount = _FALSE;
							 
					g_nNumPuzzle4Imps--;
				}
				nCount = 2;
			 }
		}
			 	 
		float fCurrentTime;
				 
		fCurrentTime = sys.getTime();
	
		if (g_nNumPuzzle4Imps < g_nNumPuzzle4MaxImps &&
			(fCurrentTime - g_fPuzzle4ImpLastTime) >= g_fPuzzle4ImpSpawnInterval)
		{
			g_fPuzzle4ImpSpawnInterval = sys.random(g_fPuzzle4ImpTimeLapse);
			g_fPuzzle4ImpSpawnInterval += g_fPuzzle4ImpMinSpawnTime;
						
			g_fPuzzle4ImpLastTime = sys.getTime();
						
			float nRandomImpSpawn; 
						
			nRandomImpSpawn = randomInt(g_nNumPuzzle4RotatingPlatforms - 1);
			nRandomImpSpawn += 1;
				 
			float		nFirstDeadImp;
			float		nCount2;
				 
			nFirstDeadImp	= 0;
			nCount		= 2;
			nCount2		= 2;
				 
			for (i = 1; i <= 2*g_nNumPuzzle4MaxImps; i++)
			{	
				nCount--;
						
				if ($puzzle4_imp_count.getIntKey("imp_"+i) == _DEAD)
				{
					nCount2--;
				}
						
				if (nFirstDeadImp == 0 && 
					nCount == 0 &&
					nCount2 == 0 && 
					$puzzle4_imp_count.getIntKey("imp_"+i) == _DEAD)
				{
					nFirstDeadImp	= i;
				}
						
				if (nCount == 0)
				{
					nCount	= 2;
					nCount2	= 2;
				}
			}
			
			if (nFirstDeadImp > 0)
			{
				// Check that nothing is blocking the area the imp is spawning from
						
				boolean	 bIsRoomToSpawnImp;
							 
				float		 fRadius;
				float		 fDistance;
							
				entity	 barrier;
				entity	 platform;
						
				vector barrierPosition;
				vector platformPosition;	
				vector impPosition;		 
				vector playerPosition;
							 
				bIsRoomToSpawnImp = _TRUE;
						
				fRadius		= 48.0;
						
				platform		= sys.getEntity("puzzle4_rotating_platform_"+nRandomImpSpawn);
				barrier		= sys.getEntity("puzzle4_blocking_volume_"+nRandomImpSpawn);
						
				for (i = 0; i < 2*g_nNumPuzzle4MaxImps; i++)
				{
					imp = sys.getEntity("puzzle4_imp_"+i);
							 
					 if (imp != $null_entity)
					 {
						impPosition 	= imp.getWorldOrigin();
									
						platformPosition	= platform.getWorldOrigin();
						platformPosition_z	= impPosition_z; 
									
						fDistance 		= imp.distanceToPoint(platformPosition);
									
						if (fDistance <= fRadius)
						{
							bIsRoomToSpawnImp = _FALSE;	 
						}
					}
				}
						
				playerPosition 	= $player1.getWorldOrigin();
						
				platformPosition	= platform.getWorldOrigin();
				platformPosition_z	= playerPosition_z; 
									
				fDistance 		= $player1.distanceToPoint(platformPosition);
									
				if (fDistance <= fRadius)
				{
					bIsRoomToSpawnImp = _FALSE;	 
				}
									
				if (bIsRoomToSpawnImp)
				{
					g_nNumPuzzle4Imps++;

					nFirstDeadImp--;
							 
					barrierPosition = barrier.getWorldOrigin();
							 
					barrierPosition_z += 64.0;
							 
					barrier.setWorldOrigin(barrierPosition);
							 
					thread activatePuzzle4RotatePlatform(nRandomImpSpawn,nFirstDeadImp);
				}
			}
		}
		sys.wait(0.1);
	 }
}

void startPuzzle4()
{
	 thread startPuzzle4RotatingAndSpawn(); 
	 //sys.killthread("startPuzzle4");
}

void activatePuzzle4()
{
	 thread startPuzzle4();
}

void endPuzzle4()
{
	 sys.killthread("startPuzzle4RotatingAndSpawn");
	 
	 entity imp;
	 
	 float i;
	 
	 for (i = 1; i <= 2*g_nNumPuzzle4MaxImps; i++)
	 {				 
		imp = sys.getEntity("puzzle4_imp_"+i);
		 
		if (imp != $null_entity)
		{	
			imp.kill();
		}
	 }
	 
	 entity hellknight;
	 
	 hellknight = sys.getEntity("puzzle4_hellknight");
	 
	 if (hellknight != $null_entity)
	 {
		hellknight.kill();
	 }
	 
	 movePuzzleDoor(_PUZZLE_4,_EXIT,_OPEN);
}

/******************************************/
/*********** PUZZLE 4 - END *************/
/******************************************/