void PointArrayParticleSystem::setParticleVelocity(Vector& vel, const Vector& dir, float speed, const GenParticleSystemEditables& eds) 
{
	
	if(m_parray.get()==NULL)
		return;
	
	bool forceDirection = !use_explosion && (eds.launchDirectionType == GenParticleSystemEditables::DIRECTION_EXPLOSION || eds.launchDirectionType == GenParticleSystemEditables::DIRECTION_NEGATIVE_EXPLOSION);
	if(m_eds->useNormalsAsDirection || forceDirection)
	{
		if(m_eds->useBinormalsAsDirection)
		{
			//VC3 up = VC3(0,1,0);
			VC3 up = VC3((rand() % 1000) / 1000.0f, (rand() % 1000) / 1000.0f, (rand() % 1000) / 1000.0f);
			VC3 binormal = up.GetCrossWith(m_parray->normals[m_index]);
			vel = binormal * speed;	
			m_rotation.RotateVector(vel);
		} else {
			vel = m_parray->normals[m_index] * speed;	
			m_rotation.RotateVector(vel);
		}
	}
	else
		vel = dir * speed;
}
예제 #2
0
void ClawUnitActor::actDirectClawControls(Unit *unit)
{
	int weapTypeNum = 0;
	static int rotating = 0;
  static bool claw_near = true;

	UnitType *unitType = unit->getUnitType();

	if (rotating) rotating--;

	// For longer claw -> 5.5, 5.0

	const game::ControlSettings &controlSettings = game->getClawController()->getControlSettings();
	if(game->getClawController()->hasActor())
	{
		if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) 
		 claw_near = false;
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) 
		 claw_near = true;
	}
	else
	{
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) 
		 claw_near = false;
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) 
		 claw_near = true;
	}

	//bool sprint_key = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_SPRINT, unit);

	bool sprint = false;
	// TODO: ask the clawcontroller if we should sprint - if claw (= pad aiming/mouse) is not moving?
	// if sprint key is pressed, then force the claw not to move

static int thefoocounter = 0;

	if (!game->getClawController()->hasActor()
		&& !game->getClawController()->isClawMoving())
	{
		thefoocounter++;
		if (thefoocounter > 67)
		{
			sprint = true;
		}
	} else {
		thefoocounter = 0;
	}

// SPRINT DISABLED FOR NOW!
sprint = false;

	if (game->getClawController()->getPrepareAction() != ClawController::ActionNone)
	{
		weapTypeNum = 6;
	} else
	{
		if(sprint)
		{
			weapTypeNum = 5;
		} else {
			if(!claw_near)
			{
				if(game->getClawController()->hasActor())
				{
					weapTypeNum = 4;
				}
				else
				{
					weapTypeNum = 2;
				}
			}
			else
			{
				if(game->getClawController()->hasActor())
				{
					weapTypeNum = 3;
				}
				else
				{
					weapTypeNum = 1;
				}
			}
		}
	}

	bool weaponAnimationTypeChanged = false;

	// HACK: hack hack hack static!
	static int lastWeapTypeNum = -1;
	static int weaponChanging = 0;
	if (weapTypeNum != lastWeapTypeNum)
	{
		lastWeapTypeNum = weapTypeNum;
		weaponAnimationTypeChanged = true;
		weaponChanging = GAME_TICKS_PER_SECOND;
	}
  if (weaponChanging) weaponChanging--;
	int anim = ANIM_STAND_TYPE0 + weapTypeNum;

	// get the controls...
	bool up = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_FORWARD, unit);
	bool left = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_LEFT, unit);
	bool right = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_RIGHT, unit);
	bool down = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_BACKWARD, unit);

	// initial control coord system (controls in camera coord sys)
	VC3 upvec = VC3(0,1,0);
	VC3 controlFrontVec = VC3(0,0,-1);
	VC3 controlSideVec = controlFrontVec.GetCrossWith(upvec);

	// HACK: hack hack hack static!
	// (if we haven't moved, this is the last moved direction)
	static VC3 controlDirVec = VC3(1,0,0);
	bool doMovement = false;

	if (up || down || left || right)
	{
		VC3 newControlDirVec = VC3(0,0,0);
		if(!game::SimpleOptions::getBool(DH_OPT_B_CLAW_MOUSE))
		{
			int jx = 0;
			int jy = 0;
			Keyb3_ReadJoystick(0, &jx, &jy, 0, 0, 0, 0);
			//if(abs(jx) < 4)
			//	jx = 0;
			//if(abs(jy) < 4)
			//	jy = 0;

			newControlDirVec -= controlSideVec * float(jx);
			newControlDirVec -= controlFrontVec * float(jy);
		}
		else
		{
			if (up)
				newControlDirVec += controlFrontVec;
			if (down)
				newControlDirVec -= controlFrontVec;
			if (left)
				newControlDirVec += controlSideVec;
			if (right)
				newControlDirVec -= controlSideVec;
		}

		if (newControlDirVec.x != 0 || newControlDirVec.y != 0 || newControlDirVec.z != 0)
		{
			newControlDirVec.Normalize();
			controlDirVec = newControlDirVec;
			doMovement = true;
		}
	}

	// camera front/side vectors (height is flattened off)
	VC3 cameraFrontVec = game->gameUI->getGameCamera()->getTargetPosition() - game->gameUI->getGameCamera()->getPosition();
	cameraFrontVec.y = 0.0f;
	if (cameraFrontVec.GetSquareLength() < 0.0001f)
	{
		cameraFrontVec = controlFrontVec;
	}
	cameraFrontVec.Normalize();
	VC3 cameraSideVec = cameraFrontVec.GetCrossWith(upvec);

	// translate movement direction from camera coord system to global ocoord. system	
	// this is the actual movement direction vector.
	VC3 globalDirVec = (cameraFrontVec * controlDirVec.GetDotWith(controlFrontVec)) + (cameraSideVec * controlDirVec.GetDotWith(controlSideVec));

	VC3 velocity = unit->getVelocity();

	// move
	if (doMovement)
	{
		float accel = unitType->getAcceleration() / GAME_TICKS_PER_SECOND;
		velocity += globalDirVec * accel;

		float maxspeed = unitType->getMaxSpeed() / GAME_TICKS_PER_SECOND;
		if (sprint)
		{
			maxspeed = unitType->getSprintSpeed() / GAME_TICKS_PER_SECOND;
		}
		if (weapTypeNum == 6)  maxspeed = unitType->getSlowSpeed() / GAME_TICKS_PER_SECOND;
		float velTotalSq = velocity.GetSquareLength();
		if (velTotalSq > maxspeed*maxspeed)
		{
			velocity *= maxspeed / (float)sqrtf(velTotalSq);
		}

	}

	// friction...
	frictionVelocity(&velocity, unitType->getFriction() * GAME_TICK_MSEC);

	unit->setVelocity(velocity);

	// where do we move to?
	float moveAngle = util::PositionDirectionCalculator::calculateDirection(VC3(0,0,0), globalDirVec);
	float rotateToAngle = moveAngle;



	bool doStrafeLeftAnim = false;
	bool doStrafeRightAnim = false;
	bool doStrafeBackAnim = false;

	static float standAngle = 0;
	
	// where do we aim?
	float aimDestAngle = moveAngle;
	char *aimBone = unitType->getAimBone();
	if (aimBone != NULL)
	{
		VC3 unitPos = unit->getPosition();

		
/*		static VC3 aimPos = VC3(0,0,0);
		VC3 aimDiff = game->getClawController()->getClawPosition() - unitPos;
		if (aimDiff.GetSquareLength() > 2.0f * 2.0f)
		{
			aimPos = game->getClawController()->getClawPosition();
		}*/
		
//		VC3 aimPos = game->getClawController()->getClawPosition();
		VC3 aimPos = game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS);

		aimDestAngle = util::PositionDirectionCalculator::calculateDirection(unitPos, aimPos);

		if (doMovement)
		{
			// --- THE HORRIBLE STRAFE LOGIC BEGINS ---
			float insideFwd = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 45.0f);
			if (insideFwd == 0)
			{
				rotateToAngle = moveAngle;
			} else {
				float insideFwdDiag = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 90.0f+45.0f);
				if (insideFwdDiag == 0)
				{
					if (insideFwd < 0)
					{
						rotateToAngle = moveAngle - 90.0f;
						if (rotateToAngle < 0.0f) rotateToAngle += 360.0f;
						doStrafeRightAnim = true;
					} else {
						rotateToAngle = moveAngle + 90.0f;
						if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
						doStrafeLeftAnim = true;
					}
				} else {
					rotateToAngle = moveAngle + 180.0f;
					if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
					doStrafeBackAnim = true;
				}
			}
			// --- THE HORRIBLE STRAFE LOGIC ENDS ---

		} else {
			if (weaponAnimationTypeChanged)
			{
				standAngle = aimDestAngle;
			}
			rotateToAngle = standAngle;

			// HACK: ...
			float maxTwist = 45.0f;
			if (weapTypeNum == 6)
			{
				maxTwist = 10.0f;
			}

			while (true)
			{
				float tooFarTwist = util::AngleRotationCalculator::getRotationForAngles(rotateToAngle, aimDestAngle, maxTwist+10);
				if (tooFarTwist > 0)
				{
					rotateToAngle += maxTwist*2;
					if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
				}
				else if (tooFarTwist < 0)
				{
					rotateToAngle -= maxTwist*2;
					if (rotateToAngle < 0.0f) rotateToAngle += 360.0f;
				} else {
					break;
				}
			}
		}
	}

	// When aiming, force rotation to dest.
	if (weapTypeNum == 6)
	{
		rotateToAngle = util::PositionDirectionCalculator::calculateDirection(
			unit->getPosition(),
			game->getClawController()->getTargetPosition(0));
	}

	if (doMovement)
	{
		standAngle = moveAngle;
		weaponChanging = GAME_TICKS_PER_SECOND / 4;
	}

	// rotate towards movement/strafe/whatever we just decided
	VC3 rot = unit->getRotation();

	float turnAccuracy = unitType->getTurningAccuracy();
	float turnSpeed = unitType->getTurning();
  // HACK, if unit is walking, slow it's turning speed down
	if (doMovement) {
		turnSpeed *= 0.7f;
	}

	float turnDir = util::AngleRotationCalculator::getRotationForAngles(rot.y, rotateToAngle, turnAccuracy);
//Logger::getInstance()->error(int2str((int)turnDir));
	rot.y += turnSpeed / GAME_TICKS_PER_SECOND * turnDir;
//	Logger::getInstance()->warning(int2str(rot.y));
//	Logger::getInstance()->warning(int2str(aimDestAngle));
	if (rotateToAngle - rot.y < -180) rotateToAngle +=360;
	if (rotateToAngle - rot.y > 180) rotateToAngle -=360;
	if (turnDir > 0 && rot.y > rotateToAngle)
	{
		rot.y = rotateToAngle;
	}
	if (turnDir < 0 && rot.y < rotateToAngle)
	{
		rot.y = rotateToAngle;
	}
	if (rot.y >= 360.0f) rot.y -= 360.0f;
	if (rot.y < 0.0f) rot.y += 360.0f;

	unit->setRotation(rot.x, rot.y, rot.z);

	// aim towards final aim direction...
	if (aimBone != NULL)
	{
		float aimAngle = aimDestAngle - rot.y;
		if (aimAngle < 0) aimAngle += 360.0f;

		unit->setLastBoneAimDirection(aimAngle);
		if (unit->getVisualObject() != NULL)
		{
			unit->getVisualObject()->rotateBone(aimBone, aimAngle, 0);
		}
	}

	// TODO: select correct animation
	if (doMovement)
	{
		if (doStrafeLeftAnim)
		{
			anim = ANIM_STRAFE_LEFT_TYPE0 + weapTypeNum;
		}
		else if (doStrafeRightAnim)
		{
			anim = ANIM_STRAFE_RIGHT_TYPE0 + weapTypeNum;
		}
		else if (doStrafeBackAnim)
		{
			anim = ANIM_RUN_BACKWARD_TYPE0 + weapTypeNum;
		} else {
			anim = ANIM_RUN_TYPE0 + weapTypeNum;
		}
	} else if (!weaponChanging) {

		// HACK: ... total hack!
		bool nappi = game->gameUI->getController(0)->isKeyDown(DH_CTRL_ATTACK_SECONDARY);

		if (turnDir < 0)
		{
			if (nappi && weapTypeNum == 4)
			{
				anim = ANIM_SPECIAL2;
			} else {
				anim = ANIM_TURN_LEFT_TYPE0 + weapTypeNum;
			}
			rotating = int(0.5*GAME_TICKS_PER_SECOND);
		}
		if (turnDir > 0)
		{
			if (nappi && weapTypeNum == 4)
			{
				anim = ANIM_SPECIAL1;
			} else {
				anim = ANIM_TURN_RIGHT_TYPE0 + weapTypeNum;
			}
			rotating = int(0.5*GAME_TICKS_PER_SECOND);
		}
	}

//Logger::getInstance()->error(int2str(anim));
	// apply the animation...
	if (unit->getAnimationSet() != NULL)
	{
		if (unit->getAnimationSet()->isAnimationInSet(anim))
		{
			unit->getAnimationSet()->animate(unit, anim);
			if (unit->getAnimationSet()->isAnimationStaticFactored(anim))
			{
				float fact = unit->getAnimationSet()->getAnimationStaticFactor(anim);
				ui::Animator::setAnimationSpeedFactor(unit, fact);
			} else {
				ui::Animator::setAnimationSpeedFactor(unit, 1.0f);
			}
		}	else {
			Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Requested anim not found in animation set.");
			Logger::getInstance()->debug("anim id number follows:");
			Logger::getInstance()->debug(int2str(anim));
		}
	} else {
		Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Unit has null animation set.");
	}
}
	// return true if position ok and decal should be added
	//        false, if position NOT ok and decal should NOT be added
	bool DecalPositionCalculator::calculateDecalPosition(
		game::GameScene *gameScene,
		const VC3 &origin, const VC3 &velocity, 
		DECAL_POSITIONING positioning, int positionRandom,
		VC3 *resultPosition, QUAT *resultRotation)
	{
		assert(positioning != DecalPositionCalculator::DECAL_POSITIONING_INVALID);

		game::GameMap *gameMap = gameScene->getGameMap();

		bool hitWall = false;

		*resultPosition = origin;
		*resultRotation = QUAT((-3.1415926f / 2.0f),0,0);

		// if velocity positioning...
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY)
		{
			VC3 velocityRandomized;
			if (positionRandom > 0)
			{
				velocityRandomized = velocity * GAME_TICKS_PER_SECOND;

	// TEMP
	//char buf[64];
	//sprintf(buf, "%f,%f,%f", velocity.x, velocity.y, velocity.z);
	//Logger::getInstance()->error(buf);

				// TODO: add positionRandom to velocity _angle_...
				// (or maybe just do a quick hack and add it to xz-coordinates?)
				velocityRandomized.x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				velocityRandomized.z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				
				// add to y too? maybe should add downward only? 
				// NOTE: biased downward
				velocityRandomized.y += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				velocityRandomized.y -= float(positionRandom) / 100.0f * 0.5f;

			} else {
				velocityRandomized = velocity;
			}

			velocityRandomized *= 2.0f;

			IStorm3D_Scene *scene = gameScene->getStormScene();

			VC3 dir = velocityRandomized.GetNormalized();			
			VC3 rayOrigin = origin;
			float rayLen = velocityRandomized.GetLength();

			Storm3D_CollisionInfo sceneColl;
			sceneColl.includeTerrainObjects = false;
			scene->RayTrace(rayOrigin, dir, rayLen, sceneColl, true);

			/*
			if (sceneColl.hit)
			{
				VC3 hitNormal = sceneColl.plane_normal;
				// make a "wall" hit if normal-y is not nearly 1
				//if (fabs(hitNormal.y) < 0.8f)
				{
					hitWall = true;

					VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
					x.Normalize();
					x -= hitNormal * x.GetDotWith(hitNormal);
					VC3 y = -x.GetCrossWith(hitNormal);

					assert(fabsf(x.GetDotWith(y)) < 0.0001f);
					assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

					MAT tm;
					tm.Set(0, x.x);
					tm.Set(1, x.y);
					tm.Set(2, x.z);
					tm.Set(4, y.x);
					tm.Set(5, y.y);
					tm.Set(6, y.z);
					tm.Set(8, hitNormal.x);
					tm.Set(9, hitNormal.y);
					tm.Set(10, hitNormal.z);

					*resultRotation = tm.GetRotation();
				}
				*resultPosition = sceneColl.position;
			} else {
				*resultPosition += velocityRandomized;
			}
			*/

			// New version
			{
				VC3 hitNormal(0, 1.f, 0);
				if(sceneColl.hit)
				{
					hitNormal = sceneColl.plane_normal;
					*resultPosition = sceneColl.position;
				}
				else
				{
					*resultPosition += velocityRandomized;
					VC2 p2(resultPosition->x, resultPosition->z);
					hitNormal = gameScene->getTerrain()->getFaceNormal(p2);
				}

				{
					if(sceneColl.hit)
						hitWall = true;

		/*
		VC3 y = dir;
		VC3 z = hitNormal;
		y -= hitNormal * y.GetDotWith(hitNormal);
		VC3 x = z.GetCrossWith(y);
		*/

		VC3 x = dir;
		x.y = 0.f;
		x.Normalize();
		x -= hitNormal * x.GetDotWith(hitNormal);
		VC3 y = -x.GetCrossWith(hitNormal);
		VC3 z = hitNormal;

		MAT tm;
		tm.Set(0, x.x);
		tm.Set(1, x.y);
		tm.Set(2, x.z);
		tm.Set(4, y.x);
		tm.Set(5, y.y);
		tm.Set(6, y.z);
		tm.Set(8, z.x);
		tm.Set(9, z.y);
		tm.Set(10, z.z);

		resultRotation->MakeFromAngles(0.f, 0.f, -PI*0.5f);
		*resultRotation = (*resultRotation) * tm.GetRotation();

					/*
					VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
					x.Normalize();
					x -= hitNormal * x.GetDotWith(hitNormal);
					VC3 y = -x.GetCrossWith(hitNormal);

					assert(fabsf(x.GetDotWith(y)) < 0.0001f);
					assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

					MAT tm;
					tm.Set(0, x.x);
					tm.Set(1, x.y);
					tm.Set(2, x.z);
					tm.Set(4, y.x);
					tm.Set(5, y.y);
					tm.Set(6, y.z);
					tm.Set(8, hitNormal.x);
					tm.Set(9, hitNormal.y);
					tm.Set(10, hitNormal.z);

					*resultRotation = tm.GetRotation();
					*/
				}
			}


			// TODO: some kind of terrain raytrace maybe...?
			// should collide to walls, etc.
		}

		// if downward positioning...
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD)
		{
			if (positionRandom > 0)
			{
				// TODO: add a random xz-offset to result position
				//*resultPosition += randomizedOffset;
				resultPosition->x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				resultPosition->z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
			}			

			/*
			// psd
			{
				VC2 p2(resultPosition->x, resultPosition->z);
				VC3 hitNormal = gameScene->getTerrain()->getFaceNormal(p2);

				VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
				x.Normalize();
				x -= hitNormal * x.GetDotWith(hitNormal);
				VC3 y = -x.GetCrossWith(hitNormal);

				assert(fabsf(x.GetDotWith(y)) < 0.0001f);
				assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

				MAT tm;
				tm.Set(0, x.x);
				tm.Set(1, x.y);
				tm.Set(2, x.z);
				tm.Set(4, y.x);
				tm.Set(5, y.y);
				tm.Set(6, y.z);
				tm.Set(8, hitNormal.x);
				tm.Set(9, hitNormal.y);
				tm.Set(10, hitNormal.z);

				*resultRotation = tm.GetRotation();
			}
			*/
			VC3 fooNormal;
			calculateDecalRotation(gameScene, *resultPosition, *resultRotation, 0.f, fooNormal);
		}

		// now check that we're still inside map boundaries
		if (!gameMap->isWellInScaledBoundaries(resultPosition->x, resultPosition->z))
		{
			// out of map.
			return false;
		}

		// then fix decal height to ground height
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD
			|| positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY)
		{
			if (!hitWall)
			{
				resultPosition->y = gameMap->getScaledHeightAt(resultPosition->x, resultPosition->z);
			}
		}

		// check that not on top of metal grid area...
		if (game::MaterialManager::isMaterialUnderPosition(gameMap, 
			*resultPosition, MATERIAL_METAL_GRATE))
		{
			// on top of grid, no decal here.
			return false;
		}

		// TODO: check that not inside a wall, terrainobject, etc.
		// if so, return false

		return true;
	}