Example #1
0
//Flags as defined by the cob standard
void CUnitScript::Explode(int piece, int flags)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber for explode");
		return;
	}

#ifndef _CONSOLE
	const float3 relPos = GetPiecePos(piece);
	const float3 absPos = unit->GetObjectSpacePos(relPos);

#ifdef TRACE_SYNC
	tracefile << "Cob explosion: ";
	tracefile << absPos.x << " " << absPos.y << " " << absPos.z << " " << piece << " " << flags << "\n";
#endif

	if (!(flags & PF_NoHeatCloud)) {
		// Do an explosion at the location first
		new CHeatCloudProjectile(nullptr, absPos, ZeroVector, 30, 30);
	}

	// If this is true, no stuff should fly off
	if (flags & PF_NONE)
		return;

	if (pieces[piece]->original == nullptr)
		return;

	if (flags & PF_Shatter) {
		Shatter(piece, absPos, unit->speed);
		return;
	}

	// This means that we are going to do a full fledged piece explosion!
	float3 baseSpeed = unit->speed;
	float3 explSpeed((0.5f - gs->randFloat()) * 6.0f, 1.2f + gs->randFloat() * 5.0f, (0.5f - gs->randFloat()) * 6.0f);

	if (unit->pos.y - CGround::GetApproximateHeight(unit->pos.x, unit->pos.z) > 15)
		explSpeed.y = (0.5f - gs->randFloat()) * 6.0f;

	if (baseSpeed.SqLength() > 9.0f) {
		const float l  = baseSpeed.Length();
		const float l2 = 3.0f + math::sqrt(l - 3.0f);
		baseSpeed *= (l2 / l);
	}

	explSpeed += baseSpeed;

	const float partSat = projectileHandler->GetParticleSaturation();

	int newFlags = 0;
	newFlags |= (PF_Explode    * ((flags & PF_Explode   ) != 0));
	newFlags |= (PF_Smoke      * ((flags & PF_Smoke     ) != 0) && partSat < 0.95f);
	newFlags |= (PF_Fire       * ((flags & PF_Fire      ) != 0) && partSat < 0.95f);
	newFlags |= (PF_NoCEGTrail * ((flags & PF_NoCEGTrail) != 0));
	newFlags |= (PF_Recursive  * ((flags & PF_Recursive ) != 0));

	new CPieceProjectile(unit, pieces[piece], absPos, explSpeed, newFlags, 0.5f);
#endif
}
Example #2
0
int CUnitScript::ScriptToModel(int scriptPieceNum) const {
	if (!PieceExists(scriptPieceNum))
		return -1;

	const LocalModelPiece* smp = GetScriptLocalModelPiece(scriptPieceNum);

	return (smp->GetLModelPieceIndex());
}
Example #3
0
void CUnitScript::SetVisibility(int piece, bool visible)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber");
		return;
	}

	pieces[piece]->scriptSetVisible = visible;
}
Example #4
0
void CUnitScript::MoveNow(int piece, int axis, float destination)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	LocalModelPiece* p = pieces[piece];
	p->pos[axis] = pieces[piece]->original->offset[axis] + destination;
}
Example #5
0
void CUnitScript::TurnNow(int piece, int axis, float destination)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	LocalModelPiece* p = pieces[piece];
	p->rot[axis] = destination;
}
Example #6
0
void CUnitScript::SetVisibility(int piece, bool visible)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	LocalModelPiece* p = pieces[piece];
	if (p->visible != visible) {
		p->visible = visible;
	}
}
Example #7
0
void CUnitScript::AttachUnit(int piece, int u)
{
	// -1 is valid, indicates that the unit should be hidden
	if ((piece >= 0) && (!PieceExists(piece))) {
		ShowUnitScriptError("Invalid piecenumber for attach");
		return;
	}

#ifndef _CONSOLE
	if (unit->unitDef->IsTransportUnit() && unitHandler->units[u]) {
		unit->AttachUnit(unitHandler->units[u], piece);
	}
#endif
}
Example #8
0
void CUnitScript::ShowFlare(int piece)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber for show(flare)");
		return;
	}
#ifndef _CONSOLE
	const float3 relPos = GetPiecePos(piece);
	const float3 absPos = unit->GetObjectSpacePos(relPos);
	const float3 dir = unit->lastMuzzleFlameDir;
	const float size = unit->lastMuzzleFlameSize;

	new CMuzzleFlame(absPos, unit->speed, dir, size);
#endif
}
Example #9
0
void CUnitScript::AttachUnit(int piece, int u)
{
	// -1 is valid, indicates that the unit should be hidden
	if ((piece >= 0) && (!PieceExists(piece))) {
		ShowScriptError("Invalid piecenumber for attach");
		return;
	}

#ifndef _CONSOLE
	CTransportUnit* tu = dynamic_cast<CTransportUnit*>(unit);

	if (tu && uh->units[u]) {
		tu->AttachUnit(uh->units[u], piece);
	}
#endif
}
Example #10
0
void CUnitScript::MoveNow(int piece, int axis, float destination)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber");
		return;
	}

	LocalModel* m = unit->localModel;
	LocalModelPiece* p = pieces[piece];

	float3 pos = p->GetPosition();
	pos[axis] = pieces[piece]->original->offset[axis] + destination;

	p->SetPosition(pos);
	m->PieceUpdated(piece);
}
Example #11
0
void CUnitScript::TurnNow(int piece, int axis, float destination)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber");
		return;
	}

	LocalModel* m = unit->localModel;
	LocalModelPiece* p = pieces[piece];

	float3 rot = p->GetRotation();
	rot[axis] = destination;

	p->SetRotation(rot);
	m->PieceUpdated(piece);
}
Example #12
0
//Overwrites old information. This means that threads blocking on turn completion
//will now wait for this new turn instead. Not sure if this is the expected behaviour
//Other option would be to kill them. Or perhaps unblock them.
void CUnitScript::AddAnim(AnimType type, int piece, int axis, float speed, float dest, float accel, bool interpolated)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	float destf;
	if (type == AMove) {
		destf = pieces[piece]->original->offset[axis] + dest;
	} else {
		destf = dest;
		if (type == ATurn) {
			ClampRad(&destf);
		}
	}

	struct AnimInfo *ai;

	//Turns override spins.. Not sure about the other way around? If so the system should probably be redesigned
	//to only have two types of anims.. turns and moves, with spin as a bool
	//todo: optimize, atm RemoveAnim and FindAnim search twice through all anims
	if (type == ATurn)
		RemoveAnim(ASpin, piece, axis);
	if (type == ASpin)
		RemoveAnim(ATurn, piece, axis);

	ai = FindAnim(type, piece, axis);
	if (!ai) {
		// If we were not animating before, inform the engine of this so it can schedule us
		if (anims.empty()) {
			GUnitScriptEngine.AddInstance(this);
		}

		ai = new struct AnimInfo;
		ai->type = type;
		ai->piece = piece;
		ai->axis = axis;
		anims.push_back(ai);
	}

	ai->dest  = destf;
	ai->speed = speed;
	ai->accel = accel;
	ai->interpolated = interpolated;
}
Example #13
0
void CUnitScript::ShowFlare(int piece)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for show(flare)");
		return;
	}
#ifndef _CONSOLE
	const float3 relPos = GetPiecePos(piece);
	const float3 absPos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;
	const float3 dir = unit->lastMuzzleFlameDir;
	const float size = unit->lastMuzzleFlameSize;

	new CMuzzleFlame(absPos, unit->speed, dir, size);
#endif
}
Example #14
0
void CUnitScript::TurnSmooth(int piece, int axis, float destination, int delta, int deltaTime)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	AnimInfo *ai = FindAnim(ATurn, piece, axis);
	if (ai) {
		if (!ai->interpolated) {
			TurnNow(piece, axis, destination);
			return;
		}
	}

	// not sure the ClampRad() call is necessary here
	float cur = ClampRad(pieces[piece]->rot[axis]);
	float dist = streflop::fabsf(destination - cur);
	int timeFactor = (1000 * 1000) / (deltaTime * deltaTime);
	float speed = (dist * timeFactor) / delta;

	Turn(piece, axis, speed, destination, true);
}
Example #15
0
void CUnitScript::MoveSmooth(int piece, int axis, float destination, int delta, int deltaTime)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	//Make sure we do not overwrite animations of non-interpolated origin
	AnimInfo *ai = FindAnim(AMove, piece, axis);
	if (ai) {
		if (!ai->interpolated) {
			MoveNow(piece, axis, destination);
			return;
		}
	}

	float cur = pieces[piece]->pos[axis] - pieces[piece]->original->offset[axis];
	float dist = streflop::fabsf(destination - cur);
	int timeFactor = (1000 * 1000) / (deltaTime * deltaTime);
	float speed = (dist * timeFactor) / delta;

	Move(piece, axis, speed, destination, true);
}
Example #16
0
int CUnitScript::GetUnitVal(int val, int p1, int p2, int p3, int p4)
{
	// may happen in case one uses Spring.GetUnitCOBValue (Lua) on a unit with CNullUnitScript
	if (!unit) {
		ShowScriptError("Error: no unit (in GetUnitVal)");
		return 0;
	}

#ifndef _CONSOLE
	switch (val)
	{
	case ACTIVATION:
		if (unit->activated)
			return 1;
		else
			return 0;
		break;
	case STANDINGMOVEORDERS:
		return unit->moveState;
		break;
	case STANDINGFIREORDERS:
		return unit->fireState;
		break;
	case HEALTH: {
		if (p1 <= 0)
			return int((unit->health / unit->maxHealth) * 100.0f);

		const CUnit* u = uh->GetUnit(p1);

		if (u == NULL)
			return 0;
		else
			return int((u->health / u->maxHealth) * 100.0f);
	}
	case INBUILDSTANCE:
		if (unit->inBuildStance)
			return 1;
		else
			return 0;
	case BUSY:
		if (busy)
			return 1;
		else
			return 0;
		break;
	case PIECE_XZ: {
		if (!PieceExists(p1)) {
			ShowScriptError("Invalid piecenumber for get piece_xz");
			break;
		}
		const float3 relPos = GetPiecePos(p1);
		const float3 absPos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x;
		return PACKXZ(absPos.x, absPos.z);
	}
	case PIECE_Y: {
		if (!PieceExists(p1)) {
			ShowScriptError("Invalid piecenumber for get piece_y");
			break;
		}
		const float3 relPos = GetPiecePos(p1);
		const float3 absPos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x;
		return int(absPos.y * COBSCALE);
	}
	case UNIT_XZ: {
		if (p1 <= 0)
			return PACKXZ(unit->pos.x, unit->pos.z);

		const CUnit* u = uh->GetUnit(p1);

		if (u == NULL)
			return PACKXZ(0, 0);
		else
			return PACKXZ(u->pos.x, u->pos.z);
	}
	case UNIT_Y: {
		if (p1 <= 0)
			return int(unit->pos.y * COBSCALE);

		const CUnit* u = uh->GetUnit(p1);

		if (u == NULL)
			return 0;
		else
			return int(u->pos.y * COBSCALE);
	}
	case UNIT_HEIGHT: {
		if (p1 <= 0)
			return int(unit->radius * COBSCALE);

		const CUnit* u = uh->GetUnit(p1);

		if (u == NULL)
			return 0;
		else
			return int(u->radius * COBSCALE);
	}
	case XZ_ATAN:
		return int(RAD2TAANG*math::atan2((float)UNPACKX(p1), (float)UNPACKZ(p1)) + 32768 - unit->heading);
	case XZ_HYPOT:
		return int(math::hypot((float)UNPACKX(p1), (float)UNPACKZ(p1)) * COBSCALE);
	case ATAN:
		return int(RAD2TAANG*math::atan2((float)p1, (float)p2));
	case HYPOT:
		return int(math::hypot((float)p1, (float)p2));
	case GROUND_HEIGHT:
		return int(ground->GetHeightAboveWater(UNPACKX(p1), UNPACKZ(p1)) * COBSCALE);
	case GROUND_WATER_HEIGHT:
		return int(ground->GetHeightReal(UNPACKX(p1), UNPACKZ(p1)) * COBSCALE);
	case BUILD_PERCENT_LEFT:
		return int((1.0f - unit->buildProgress) * 100);

	case YARD_OPEN:
		if (yardOpen)
			return 1;
		else
			return 0;
	case BUGGER_OFF:
		break;
	case ARMORED:
		if (unit->armoredState)
			return 1;
		else
			return 0;
	case VETERAN_LEVEL:
		return int(100 * unit->experience);
	case CURRENT_SPEED:
		return int(unit->speed.Length() * COBSCALE);
	case ON_ROAD:
		return 0;
	case IN_WATER:
		return (unit->pos.y < 0.0f) ? 1 : 0;
	case MAX_ID:
		return uh->MaxUnits()-1;
	case MY_ID:
		return unit->id;

	case UNIT_TEAM: {
		const CUnit* u = uh->GetUnit(p1);
		return (u != NULL)? unit->team : 0;
	}
	case UNIT_ALLIED: {
		const CUnit* u = uh->GetUnit(p1);

		if (u != NULL) {
			return teamHandler->Ally(unit->allyteam, u->allyteam) ? 1 : 0;
		}

		return 0;
	}
	case UNIT_BUILD_PERCENT_LEFT: {
		const CUnit* u = uh->GetUnit(p1);

		if (u != NULL) {
			return int((1.0f - u->buildProgress) * 100);
		}

		return 0;
	}
	case MAX_SPEED: {
		return int(unit->moveType->GetMaxSpeed() * COBSCALE);
	} break;
	case REVERSING: {
		CGroundMoveType* gmt = dynamic_cast<CGroundMoveType*>(unit->moveType);
		return ((gmt != NULL)? int(gmt->IsReversing()): 0);
	} break;
	case CLOAKED:
		return !!unit->isCloaked;
	case WANT_CLOAK:
		return !!unit->wantCloak;
	case UPRIGHT:
		return !!unit->upright;
	case POW:
		return int(math::pow(((float)p1)/COBSCALE,((float)p2)/COBSCALE)*COBSCALE);
	case PRINT:
		LOG("Value 1: %d, 2: %d, 3: %d, 4: %d", p1, p2, p3, p4);
		break;
	case HEADING: {
		if (p1 <= 0) {
			return unit->heading;
		}

		const CUnit* u = uh->GetUnit(p1);

		if (u != NULL) {
			return u->heading;
		}

		return -1;
	}
	case TARGET_ID: {
		if (unit->weapons[p1 - 1]) {
			const CWeapon* weapon = unit->weapons[p1 - 1];
			const TargetType tType = weapon->targetType;

			if (tType == Target_Unit)
				return unit->weapons[p1 - 1]->targetUnit->id;
			else if (tType == Target_None)
				return -1;
			else if (tType == Target_Pos)
				return -2;
			else // Target_Intercept
				return -3;
		}
		return -4; // weapon does not exist
	}

	case LAST_ATTACKER_ID:
		return unit->lastAttacker? unit->lastAttacker->id: -1;
	case LOS_RADIUS:
		return unit->realLosRadius;
	case AIR_LOS_RADIUS:
		return unit->realAirLosRadius;
	case RADAR_RADIUS:
		return unit->radarRadius;
	case JAMMER_RADIUS:
		return unit->jammerRadius;
	case SONAR_RADIUS:
		return unit->sonarRadius;
	case SONAR_JAM_RADIUS:
		return unit->sonarJamRadius;
	case SEISMIC_RADIUS:
		return unit->seismicRadius;

	case DO_SEISMIC_PING:
		float pingSize;
		if (p1 == 0) {
			pingSize = unit->seismicSignature;
		} else {
			pingSize = p1;
		}
		unit->DoSeismicPing(pingSize);
		break;

	case CURRENT_FUEL:
		return int(unit->currentFuel * float(COBSCALE));
	case TRANSPORT_ID:
		return unit->transporter?unit->transporter->id:-1;

	case SHIELD_POWER: {
		if (unit->shieldWeapon == NULL) {
			return -1;
		}
		const CPlasmaRepulser* shield = (CPlasmaRepulser*) unit->shieldWeapon;
		return int(shield->curPower * float(COBSCALE));
	}

	case STEALTH: {
		return unit->stealth ? 1 : 0;
	}
	case SONAR_STEALTH: {
		return unit->sonarStealth ? 1 : 0;
	}
	case CRASHING:
		return !!unit->crashing;
	case ALPHA_THRESHOLD: {
		return int(unit->alphaThreshold * 255);
	}

	case COB_ID: {
		if (p1 <= 0) {
			return unit->unitDef->cobID;
		} else {
			const CUnit* u = uh->GetUnit(p1);
			return ((u == NULL)? -1 : u->unitDef->cobID);
		}
	}

 	case PLAY_SOUND: {
 		// FIXME: this can currently only work for CCobInstance, because Lua can not get sound IDs
 		// (however, for Lua scripts there is already LuaUnsyncedCtrl::PlaySoundFile)
 		CCobInstance* cob = dynamic_cast<CCobInstance*>(this);
 		if (cob == NULL) {
 			return 1;
 		}
 		const CCobFile* script = cob->GetScriptAddr();
 		if (script == NULL) {
 			return 1;
 		}
		if ((p1 < 0) || (static_cast<size_t>(p1) >= script->sounds.size())) {
			return 1;
		}
		switch (p3) {	//who hears the sound
			case 0:		//ALOS
				if (!loshandler->InAirLos(unit->pos,gu->myAllyTeam)) { return 0; }
				break;
			case 1:		//LOS
				if (!(unit->losStatus[gu->myAllyTeam] & LOS_INLOS)) { return 0; }
				break;
			case 2:		//ALOS or radar
				if (!(loshandler->InAirLos(unit->pos,gu->myAllyTeam) || unit->losStatus[gu->myAllyTeam] & (LOS_INRADAR))) { return 0; }
				break;
			case 3:		//LOS or radar
				if (!(unit->losStatus[gu->myAllyTeam] & (LOS_INLOS | LOS_INRADAR))) { return 0; }
				break;
			case 4:		//everyone
				break;
			case 5:		//allies
				if (unit->allyteam != gu->myAllyTeam) { return 0; }
				break;
			case 6:		//team
				if (unit->team != gu->myTeam) { return 0; }
				break;
			case 7:		//enemies
				if (unit->allyteam == gu->myAllyTeam) { return 0; }
				break;
		}
		if (p4 == 0) {
			Channels::General.PlaySample(script->sounds[p1], unit->pos, unit->speed, float(p2) / COBSCALE);
		} else {
			Channels::General.PlaySample(script->sounds[p1], float(p2) / COBSCALE);
		}
		return 0;
	}
	case SET_WEAPON_UNIT_TARGET: {
		const unsigned int weaponID = p1 - 1;
		const unsigned int targetID = p2;
		const bool userTarget = !!p3;

		if (weaponID >= unit->weapons.size()) {
			return 0;
		}

		CWeapon* weapon = unit->weapons[weaponID];

		if (weapon == NULL) {
			return 0;
		}

		//! if targetID is 0, just sets weapon->haveUserTarget
		//! to false (and targetType to None) without attacking
		CUnit* target = (targetID > 0)? uh->GetUnit(targetID): NULL;
		return (weapon->AttackUnit(target, userTarget) ? 1 : 0);
	}
	case SET_WEAPON_GROUND_TARGET: {
		const int weaponID = p1 - 1;
		const float3 pos = float3(float(UNPACKX(p2)),
		                          float(p3) / float(COBSCALE),
		                          float(UNPACKZ(p2)));
		const bool userTarget = !!p4;
		if ((weaponID < 0) || (static_cast<size_t>(weaponID) >= unit->weapons.size())) {
			return 0;
		}
		CWeapon* weapon = unit->weapons[weaponID];
		if (weapon == NULL) { return 0; }

		return weapon->AttackGround(pos, userTarget) ? 1 : 0;
	}
	case MIN:
		return std::min(p1, p2);
	case MAX:
		return std::max(p1, p2);
	case ABS:
		return abs(p1);
	case KSIN:
		return int(1024*math::sinf(TAANG2RAD*(float)p1));
	case KCOS:
		return int(1024*math::cosf(TAANG2RAD*(float)p1));
	case KTAN:
		return int(1024*math::tanf(TAANG2RAD*(float)p1));
	case SQRT:
		return int(math::sqrt((float)p1));
	case FLANK_B_MODE:
		return unit->flankingBonusMode;
	case FLANK_B_DIR:
		switch (p1) {
			case 1: return int(unit->flankingBonusDir.x * COBSCALE);
			case 2: return int(unit->flankingBonusDir.y * COBSCALE);
			case 3: return int(unit->flankingBonusDir.z * COBSCALE);
			case 4: unit->flankingBonusDir.x = (p2/(float)COBSCALE); return 0;
			case 5: unit->flankingBonusDir.y = (p2/(float)COBSCALE); return 0;
			case 6: unit->flankingBonusDir.z = (p2/(float)COBSCALE); return 0;
			case 7: unit->flankingBonusDir = float3(p2/(float)COBSCALE, p3/(float)COBSCALE, p4/(float)COBSCALE).Normalize(); return 0;
			default: return(-1);
		}
	case FLANK_B_MOBILITY_ADD:
		return int(unit->flankingBonusMobilityAdd * COBSCALE);
	case FLANK_B_MAX_DAMAGE:
		return int((unit->flankingBonusAvgDamage + unit->flankingBonusDifDamage) * COBSCALE);
	case FLANK_B_MIN_DAMAGE:
		return int((unit->flankingBonusAvgDamage - unit->flankingBonusDifDamage) * COBSCALE);
	case KILL_UNIT: {
		//! ID 0 is reserved for the script's owner
		CUnit* u = (p1 > 0)? uh->GetUnit(p1): this->unit;

		if (u == NULL) {
			return 0;
		}

		if (u->beingBuilt) {
			// no explosions and no corpse for units under construction
			u->KillUnit(false, true, NULL);
		} else {
			u->KillUnit(p2 != 0, p3 != 0, NULL);
		}

		return 1;
	}
	case WEAPON_RELOADSTATE: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return unit->weapons[p1-1]->reloadStatus;
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->reloadStatus;
			unit->weapons[np1 - 1]->reloadStatus = p2;
			return old;
		}
		else {
			return -1;
		}
	}
	case WEAPON_RELOADTIME: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return unit->weapons[p1-1]->reloadTime;
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->reloadTime;
			unit->weapons[np1 - 1]->reloadTime = p2;
			return old;
		}
		else {
			return -1;
		}
	}
	case WEAPON_ACCURACY: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return int(unit->weapons[p1-1]->accuracy * COBSCALE);
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->accuracy * COBSCALE;
			unit->weapons[np1 - 1]->accuracy = float(p2) / COBSCALE;
			return old;
		}
		else {
			return -1;
		}
	}
	case WEAPON_SPRAY: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return int(unit->weapons[p1-1]->sprayAngle * COBSCALE);
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->sprayAngle * COBSCALE;
			unit->weapons[np1 - 1]->sprayAngle = float(p2) / COBSCALE;
			return old;
		}
		else {
			return -1;
		}
	}
	case WEAPON_RANGE: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return int(unit->weapons[p1 - 1]->range * COBSCALE);
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->range * COBSCALE;
			unit->weapons[np1 - 1]->range = float(p2) / COBSCALE;
			return old;
		}
		else {
			return -1;
		}
	}
	case WEAPON_PROJECTILE_SPEED: {
		const int np1 = -p1;
		if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) {
			return int(unit->weapons[p1-1]->projectileSpeed * COBSCALE);
		}
		else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) {
			const int old = unit->weapons[np1 - 1]->projectileSpeed * COBSCALE;
			unit->weapons[np1 - 1]->projectileSpeed = float(p2) / COBSCALE;
			return old;
		}
		else {
			return -1;
		}
	}
	case GAME_FRAME: {
		return gs->frameNum;
	}
	default:
		if ((val >= GLOBAL_VAR_START) && (val <= GLOBAL_VAR_END)) {
			return globalVars[val - GLOBAL_VAR_START];
		}
		else if ((val >= TEAM_VAR_START) && (val <= TEAM_VAR_END)) {
			return teamVars[unit->team][val - TEAM_VAR_START];
		}
		else if ((val >= ALLY_VAR_START) && (val <= ALLY_VAR_END)) {
			return allyVars[unit->allyteam][val - ALLY_VAR_START];
		}
		else if ((val >= UNIT_VAR_START) && (val <= UNIT_VAR_END)) {
			const int varID = val - UNIT_VAR_START;

			if (p1 == 0) {
				return unitVars[varID];
			}
			else if (p1 > 0) {
				// get the unit var for another unit
				const CUnit* u = uh->GetUnit(p1);

				if (u != NULL && u->script != NULL) {
					return u->script->unitVars[varID];
				}
			}
			else {
				// set the unit var for another unit
				p1 = -p1;

				CUnit* u = uh->GetUnit(p1);

				if (u != NULL && u->script != NULL) {
					u->script->unitVars[varID] = p2;
					return 1;
				}
			}
			return 0;
		}
		else {
			LOG_L(L_ERROR,
					"CobError: Unknown get constant %d (params = %d %d %d %d)",
					val, p1, p2, p3, p4);
		}
	}
#endif

	return 0;
}
Example #17
0
//Flags as defined by the cob standard
void CUnitScript::Explode(int piece, int flags)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for explode");
		return;
	}

#ifndef _CONSOLE
	const float3 relPos = GetPiecePos(piece);
	const float3 absPos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;

#ifdef TRACE_SYNC
	tracefile << "Cob explosion: ";
	tracefile << absPos.x << " " << absPos.y << " " << absPos.z << " " << piece << " " << flags << "\n";
#endif

	if (!(flags & PF_NoHeatCloud)) {
		// Do an explosion at the location first
		new CHeatCloudProjectile(absPos, float3(0, 0, 0), 30, 30, NULL);
	}

	// If this is true, no stuff should fly off
	if (flags & PF_NONE) return;

	// This means that we are going to do a full fledged piece explosion!
	float3 baseSpeed = unit->speed + unit->residualImpulse * 0.5f;
	float sql = baseSpeed.SqLength();

	if (sql > 9) {
		const float l  = math::sqrt(sql);
		const float l2 = 3 + math::sqrt(l - 3);
		baseSpeed *= (l2 / l);
	}
	float3 speed((0.5f-gs->randFloat()) * 6.0f, 1.2f + gs->randFloat() * 5.0f, (0.5f - gs->randFloat()) * 6.0f);
	if (unit->pos.y - ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 15) {
		speed.y = (0.5f - gs->randFloat()) * 6.0f;
	}
	speed += baseSpeed;
	if (speed.SqLength() > 12*12) {
		speed.Normalize();
		speed *= 12;
	}

	/* TODO Push this back. Don't forget to pass the team (color).  */

	if (flags & PF_Shatter) {
		Shatter(piece, absPos, speed);
	}
	else {
		LocalModelPiece* pieceData = pieces[piece];

		if (pieceData->original != NULL) {
			int newflags = PF_Fall; // if they don't fall they could live forever
			if (flags & PF_Explode) { newflags |= PF_Explode; }
			//if (flags & PF_Fall) { newflags |=  PF_Fall; }
			if ((flags & PF_Smoke) && ph->particleSaturation < 1) { newflags |= PF_Smoke; }
			if ((flags & PF_Fire) && ph->particleSaturation < 0.95f) { newflags |= PF_Fire; }
			if (flags & PF_NoCEGTrail) { newflags |= PF_NoCEGTrail; }

			//LOG_L(L_DEBUG, "Exploding %s as %d", script.pieceNames[piece].c_str(), dl);
			new CPieceProjectile(absPos, speed, pieceData, newflags,unit,0.5f);
		}
	}
#endif
}
Example #18
0
void CUnitScript::EmitSfx(int sfxType, int piece)
{
#ifndef _CONSOLE
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for emit-sfx");
		return;
	}

	if (ph->particleSaturation > 1.0f && sfxType < SFX_CEG) {
		// skip adding (unsynced!) particles when we have too many
		return;
	}

	// Make sure wakes are only emitted on water
	if ((sfxType >= SFX_WAKE) && (sfxType <= SFX_REVERSE_WAKE_2)) {
		if (ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 0.0f) {
			return;
		}
	}

	float3 relPos = ZeroVector;
	float3 relDir = UpVector;

	if (!GetEmitDirPos(piece, relPos, relDir)) {
		ShowScriptError("emit-sfx: GetEmitDirPos failed");
		return;
	}

	relDir.SafeNormalize();

	const float3 pos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;
	const float3 dir =
		unit->frontdir * relDir.z +
		unit->updir    * relDir.y +
		unit->rightdir * relDir.x;

	float alpha = 0.3f + gu->usRandFloat() * 0.2f;
	float alphaFalloff = 0.004f;
	float fadeupTime = 4;

	const UnitDef* ud = unit->unitDef;
	const MoveDef* md = ud->moveDef;

	// hovercraft need special care
	if (md != NULL && md->moveType == MoveDef::Hover_Move) {
		fadeupTime = 8.0f;
		alpha = 0.15f + gu->usRandFloat() * 0.2f;
		alphaFalloff = 0.008f;
	}

	switch (sfxType) {
		case SFX_REVERSE_WAKE:
		case SFX_REVERSE_WAKE_2: {  //reverse wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_WAKE_2:  //wake 2, in TA it lives longer..
		case SFX_WAKE: {  //regular ship wake
			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_BUBBLE: {  //submarine bubble. does not provide direction through piece vertices..
			float3 pspeed = gu->usRandVector() * 0.1f;
				pspeed.y += 0.2f;

			new CBubbleProjectile(
				pos + gu->usRandVector() * 2.0f,
				pspeed,
				40.0f + gu->usRandFloat() * 30.0f,
				1.0f + gu->usRandFloat() * 2.0f,
				0.01f,
				unit,
				0.3f + gu->usRandFloat() * 0.3f
			);
		} break;

		case SFX_WHITE_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.5f);
			break;
		case SFX_BLACK_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.6f);
			break;
		case SFX_VTOL: {
			const float3 speed =
				unit->speed    * 0.7f +
				unit->frontdir * 0.5f *       relDir.z  +
				unit->updir    * 0.5f * -math::fabs(relDir.y) +
				unit->rightdir * 0.5f *       relDir.x;

			CHeatCloudProjectile* hc = new CHeatCloudProjectile(
				pos,
				speed,
				10 + gu->usRandFloat() * 5,
				3 + gu->usRandFloat() * 2,
				unit
			);
			hc->size = 3;
			break;
		}
		default: {
			if (sfxType & SFX_CEG) {
				// emit defined explosiongenerator
				const unsigned index = sfxType - SFX_CEG;
				if (index >= unit->unitDef->sfxExplGens.size() || unit->unitDef->sfxExplGens[index] == NULL) {
					ShowScriptError("Invalid explosion generator index for emit-sfx");
					break;
				}

				IExplosionGenerator* explGen = unit->unitDef->sfxExplGens[index];
				explGen->Explosion(0, pos, unit->cegDamage, 1, unit, 0, 0, dir);
			}
			else if (sfxType & SFX_FIRE_WEAPON) {
				// make a weapon fire from the piece
				const unsigned index = sfxType - SFX_FIRE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				CWeapon* weapon = unit->weapons[index];

				const float3 targetPos = weapon->targetPos;
				const float3 weaponMuzzlePos = weapon->weaponMuzzlePos;

				weapon->targetPos = pos + dir;
				weapon->weaponMuzzlePos = pos;
				weapon->Fire();
				weapon->weaponMuzzlePos = weaponMuzzlePos;
				weapon->targetPos = targetPos;
			}
			else if (sfxType & SFX_DETONATE_WEAPON) {
				const unsigned index = sfxType - SFX_DETONATE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				// detonate weapon from piece
				const WeaponDef* weaponDef = unit->weapons[index]->weaponDef;

				CGameHelper::ExplosionParams params = {
					pos,
					ZeroVector,
					weaponDef->damages,
					weaponDef,
					unit,                              // owner
					NULL,                              // hitUnit
					NULL,                              // hitFeature
					weaponDef->craterAreaOfEffect,
					weaponDef->damageAreaOfEffect,
					weaponDef->edgeEffectiveness,
					weaponDef->explosionSpeed,
					1.0f,                              // gfxMod
					weaponDef->impactOnly,
					weaponDef->noSelfDamage,           // ignoreOwner
					true,                              // damageGround
				};

				helper->Explosion(params);
			}
		} break;
	}


#endif
}
Example #19
0
//Overwrites old information. This means that threads blocking on turn completion
//will now wait for this new turn instead. Not sure if this is the expected behaviour
//Other option would be to kill them. Or perhaps unblock them.
void CUnitScript::AddAnim(AnimType type, int piece, int axis, float speed, float dest, float accel)
{
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber");
		return;
	}

	float destf = 0.0f;

	if (type == AMove) {
		destf = pieces[piece]->original->offset[axis] + dest;
	} else {
		destf = dest;
		if (type == ATurn) {
			ClampRad(&destf);
		}
	}

	std::list<AnimInfo*>::iterator animInfoIt;
	AnimInfo* ai = NULL;
	AnimType overrideType = ANone;

	// first find an animation of a type we override
	// Turns override spins.. Not sure about the other way around? If so
	// the system should probably be redesigned to only have two types of
	// anims (turns and moves), with spin as a bool
	switch (type) {
		case ATurn: {
			overrideType = ASpin;
			animInfoIt = FindAnim(overrideType, piece, axis);
		} break;
		case ASpin: {
			overrideType = ATurn;
			animInfoIt = FindAnim(overrideType, piece, axis);
		} break;
		case AMove: {
			// ensure we never remove an animation of this type
			overrideType = AMove;
			animInfoIt = anims[overrideType].end();
		} break;
		default: {
		} break;
	}

	if (animInfoIt != anims[overrideType].end())
		RemoveAnim(overrideType, animInfoIt);

	// now find an animation of our own type
	animInfoIt = FindAnim(type, piece, axis);

	if (animInfoIt == anims[type].end()) {
		// If we were not animating before, inform the engine of this so it can schedule us
		// FIXME: this could be done in a cleaner way
		if (!HaveAnimations()) {
			GUnitScriptEngine.AddInstance(this);
		}

		ai = new AnimInfo();
		ai->type = type;
		ai->piece = piece;
		ai->axis = axis;
		anims[type].push_back(ai);
	} else {
		ai = *animInfoIt;
	}

	ai->dest  = destf;
	ai->speed = speed;
	ai->accel = accel;
	ai->done = false;
}
Example #20
0
void CUnitScript::EmitSfx(int type, int piece)
{
#ifndef _CONSOLE
	if (!PieceExists(piece)) {
		ShowScriptError("Invalid piecenumber for emit-sfx");
		return;
	}

	if (ph->particleSaturation > 1 && type < 1024) {
		// skip adding (unsynced!) particles when we have too many
		return;
	}

	float3 relPos = ZeroVector;
	float3 relDir = UpVector;
	if (!GetEmitDirPos(piece, relPos, relDir)) {
		ShowScriptError("emit-sfx: GetEmitDirPos failed");
		return;
	}

	const float3 pos =
		unit->pos +
		unit->frontdir * relPos.z +
		unit->updir    * relPos.y +
		unit->rightdir * relPos.x;
	const float3 dir =
		unit->frontdir * relDir.z +
		unit->updir    * relDir.y +
		unit->rightdir * relDir.x;

	float alpha = 0.3f + gu->usRandFloat() * 0.2f;
	float alphaFalloff = 0.004f;
	float fadeupTime = 4;

	// Hovers need special care
	if (unit->unitDef->canhover) {
		fadeupTime = 8.0f;
		alpha = 0.15f + gu->usRandFloat() * 0.2f;
		alphaFalloff = 0.008f;
	}

	//Make sure wakes are only emitted on water
	if ((type >= 2) && (type <= 5)) {
		if (ground->GetApproximateHeight(unit->pos.x, unit->pos.z) > 0) {
			return;
		}
	}

	switch (type) {
		case SFX_REVERSE_WAKE:
		case SFX_REVERSE_WAKE_2: {  //reverse wake
			relDir *= -0.2f;

			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_WAKE_2:  //wake 2, in TA it lives longer..
		case SFX_WAKE: {  //regular ship wake
			relDir *= 0.2f;

			new CWakeProjectile(
				pos + gu->usRandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->usRandFloat() * 4.0f,
				0.15f + gu->usRandFloat() * 0.3f,
				unit,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_BUBBLE: {  //submarine bubble. does not provide direction through piece vertices..
			float3 pspeed = gu->usRandVector() * 0.1f;
				pspeed.y += 0.2f;

			new CBubbleProjectile(
				pos + gu->usRandVector() * 2.0f,
				pspeed,
				40.0f + gu->usRandFloat() * 30.0f,
				1.0f + gu->usRandFloat() * 2.0f,
				0.01f,
				unit,
				0.3f + gu->usRandFloat() * 0.3f
			);
		} break;

		case SFX_WHITE_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.5f);
			break;
		case SFX_BLACK_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(pos, gu->usRandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, unit, 0.6f);
			break;
		case SFX_VTOL: {  //vtol
			relDir *= 0.2f;

			const float3 udir =
				unit->frontdir * relDir.z +
				unit->updir    * -fabs(relDir.y) +
				unit->rightdir * relDir.x;

			CHeatCloudProjectile* hc = new CHeatCloudProjectile(
				pos,
				unit->speed * 0.7f + udir * 0.5f,
				10 + gu->usRandFloat() * 5,
				3 + gu->usRandFloat() * 2,
				unit
			);
			hc->size = 3;
			break;
		}
		default: {
			if (type & SFX_CEG) {
				// emit defined explosiongenerator
				const unsigned index = type - SFX_CEG;
				if (index >= unit->unitDef->sfxExplGens.size() || unit->unitDef->sfxExplGens[index] == NULL) {
					ShowScriptError("Invalid explosion generator index for emit-sfx");
					break;
				}

				float3 ndir = dir; 

				CExplosionGenerator* explGen = unit->unitDef->sfxExplGens[index];
				explGen->Explosion(pos, unit->cegDamage, 1, unit, 0, 0, ndir.SafeNormalize());
			}
			else if (type & SFX_FIRE_WEAPON) {
				// make a weapon fire from the piece
				const unsigned index = type - SFX_FIRE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				CWeapon* weapon = unit->weapons[index];

				const float3 targetPos = weapon->targetPos;
				const float3 weaponMuzzlePos = weapon->weaponMuzzlePos;

				float3 ndir = dir;

				// don't override the weapon's target position
				// if it was not set internally (so that force-
				// fire keeps working as expected)
				if (!weapon->haveUserTarget) {
					weapon->targetPos = pos + ndir.SafeNormalize();
				}

				weapon->weaponMuzzlePos = pos;
				weapon->Fire();
				weapon->weaponMuzzlePos = weaponMuzzlePos;

				weapon->targetPos = targetPos;
			}
			else if (type & SFX_DETONATE_WEAPON) {
				const unsigned index = type - SFX_DETONATE_WEAPON;
				if (index >= unit->weapons.size() || unit->weapons[index] == NULL) {
					ShowScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				// detonate weapon from piece
				const WeaponDef* weaponDef = unit->weapons[index]->weaponDef;

				if (weaponDef->soundhit.getID(0) > 0) {
					Channels::Battle.PlaySample(weaponDef->soundhit.getID(0), unit, weaponDef->soundhit.getVolume(0));
				}

				helper->Explosion(
					pos, weaponDef->damages, weaponDef->areaOfEffect, weaponDef->edgeEffectiveness,
					weaponDef->explosionSpeed, unit, true, 1.0f, weaponDef->noSelfDamage, weaponDef->impactOnly, weaponDef->explosionGenerator,
					NULL, float3(0, 0, 0), weaponDef->id
				);
			}
		} break;
	}


#endif
}
Example #21
0
void CUnitScript::EmitSfx(int sfxType, int piece)
{
#ifndef _CONSOLE
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber for emit-sfx");
		return;
	}

	if (projectileHandler->GetParticleSaturation() > 1.0f && sfxType < SFX_CEG) {
		// skip adding (unsynced!) particles when we have too many
		return;
	}

	// Make sure wakes are only emitted on water
	if ((sfxType >= SFX_WAKE) && (sfxType <= SFX_REVERSE_WAKE_2)) {
		if (CGround::GetApproximateHeight(unit->pos.x, unit->pos.z) > 0.0f) {
			return;
		}
	}

	float3 relPos = ZeroVector;
	float3 relDir = UpVector;

	if (!GetEmitDirPos(piece, relPos, relDir)) {
		ShowUnitScriptError("emit-sfx: GetEmitDirPos failed");
		return;
	}

	relDir.SafeNormalize();

	const float3 pos = unit->GetObjectSpacePos(relPos);
	const float3 dir = unit->GetObjectSpaceVec(relDir);

	float alpha = 0.3f + gu->RandFloat() * 0.2f;
	float alphaFalloff = 0.004f;
	float fadeupTime = 4;

	const UnitDef* ud = unit->unitDef;
	const MoveDef* md = unit->moveDef;

	// hovercraft need special care
	if (md != NULL && md->speedModClass == MoveDef::Hover) {
		fadeupTime = 8.0f;
		alpha = 0.15f + gu->RandFloat() * 0.2f;
		alphaFalloff = 0.008f;
	}

	switch (sfxType) {
		case SFX_REVERSE_WAKE:
		case SFX_REVERSE_WAKE_2: {  //reverse wake
			new CWakeProjectile(
				unit,
				pos + gu->RandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->RandFloat() * 4.0f,
				0.15f + gu->RandFloat() * 0.3f,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_WAKE_2:  //wake 2, in TA it lives longer..
		case SFX_WAKE: {  //regular ship wake
			new CWakeProjectile(
				unit,
				pos + gu->RandVector() * 2.0f,
				dir * 0.4f,
				6.0f + gu->RandFloat() * 4.0f,
				0.15f + gu->RandFloat() * 0.3f,
				alpha, alphaFalloff, fadeupTime
			);
			break;
		}

		case SFX_BUBBLE: {  //submarine bubble. does not provide direction through piece vertices..
			float3 pspeed = gu->RandVector() * 0.1f;
				pspeed.y += 0.2f;

			new CBubbleProjectile(
				unit,
				pos + gu->RandVector() * 2.0f,
				pspeed,
				40.0f + gu->RandFloat() * GAME_SPEED,
				1.0f + gu->RandFloat() * 2.0f,
				0.01f,
				0.3f + gu->RandFloat() * 0.3f
			);
		} break;

		case SFX_WHITE_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(unit, pos, gu->RandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, 0.5f);
			break;
		case SFX_BLACK_SMOKE:  //damaged unit smoke
			new CSmokeProjectile(unit, pos, gu->RandVector() * 0.5f + UpVector * 1.1f, 60, 4, 0.5f, 0.6f);
			break;
		case SFX_VTOL: {
			const float3 speed =
				unit->speed    * 0.7f +
				unit->frontdir * 0.5f *       relDir.z  +
				unit->updir    * 0.5f * -math::fabs(relDir.y) +
				unit->rightdir * 0.5f *       relDir.x;

			CHeatCloudProjectile* hc = new CHeatCloudProjectile(
				unit,
				pos,
				speed,
				10 + gu->RandFloat() * 5,
				3 + gu->RandFloat() * 2
			);
			hc->size = 3;
			break;
		}
		default: {
			if (sfxType & SFX_CEG) {
				// emit defined explosion-generator (can only be custom, not standard)
				// index is made valid by callee, an ID of -1 means CEG failed to load
				explGenHandler->GenExplosion(ud->GetModelExplosionGeneratorID(sfxType - SFX_CEG), pos, dir, unit->cegDamage, 1.0f, 0.0f, unit, NULL);
			}
			else if (sfxType & SFX_FIRE_WEAPON) {
				// make a weapon fire from the piece
				const unsigned index = sfxType - SFX_FIRE_WEAPON;
				if (index >= unit->weapons.size()) {
					ShowUnitScriptError("Invalid weapon index for emit-sfx");
					break;
				}
				CWeapon* w = unit->weapons[index];
				const SWeaponTarget origTarget = w->GetCurrentTarget();
				const float3 origWeaponMuzzlePos = w->weaponMuzzlePos;
				w->SetAttackTarget(SWeaponTarget(pos + dir));
				w->weaponMuzzlePos = pos;
				w->Fire(true);
				w->weaponMuzzlePos = origWeaponMuzzlePos;
				bool origRestored = w->Attack(origTarget);
				assert(origRestored);
			}
			else if (sfxType & SFX_DETONATE_WEAPON) {
				const unsigned index = sfxType - SFX_DETONATE_WEAPON;
				if (index >= unit->weapons.size()) {
					ShowUnitScriptError("Invalid weapon index for emit-sfx");
					break;
				}

				// detonate weapon from piece
				const WeaponDef* weaponDef = unit->weapons[index]->weaponDef;

				CGameHelper::ExplosionParams params = {
					pos,
					ZeroVector,
					weaponDef->damages,
					weaponDef,
					unit,                              // owner
					NULL,                              // hitUnit
					NULL,                              // hitFeature
					weaponDef->craterAreaOfEffect,
					weaponDef->damageAreaOfEffect,
					weaponDef->edgeEffectiveness,
					weaponDef->explosionSpeed,
					1.0f,                              // gfxMod
					weaponDef->impactOnly,
					weaponDef->noSelfDamage,           // ignoreOwner
					true,                              // damageGround
					-1u                                // projectileID
				};

				helper->Explosion(params);
			}
		} break;
	}


#endif
}
Example #22
0
//Flags as defined by the cob standard
void CUnitScript::Explode(int piece, int flags)
{
	if (!PieceExists(piece)) {
		ShowUnitScriptError("Invalid piecenumber for explode");
		return;
	}

#ifndef _CONSOLE
	const float3 relPos = GetPiecePos(piece);
	const float3 absPos = unit->GetObjectSpacePos(relPos);

#ifdef TRACE_SYNC
	tracefile << "Cob explosion: ";
	tracefile << absPos.x << " " << absPos.y << " " << absPos.z << " " << piece << " " << flags << "\n";
#endif

	if (!(flags & PF_NoHeatCloud)) {
		// Do an explosion at the location first
		new CHeatCloudProjectile(NULL, absPos, ZeroVector, 30, 30);
	}

	// If this is true, no stuff should fly off
	if (flags & PF_NONE)
		return;

	// This means that we are going to do a full fledged piece explosion!
	float3 baseSpeed = unit->speed;
	float3 explSpeed((0.5f - gs->randFloat()) * 6.0f, 1.2f + gs->randFloat() * 5.0f, (0.5f - gs->randFloat()) * 6.0f);

	if (baseSpeed.SqLength() > 9) {
		const float l  = baseSpeed.Length();
		const float l2 = 3 + math::sqrt(l - 3);
		baseSpeed *= (l2 / l);
	}
	if (unit->pos.y - CGround::GetApproximateHeight(unit->pos.x, unit->pos.z) > 15) {
		explSpeed.y = (0.5f - gs->randFloat()) * 6.0f;
	}

	explSpeed += baseSpeed;

	// limit projectile speed to 12 elmos/frame (why?)
	if (false && explSpeed.SqLength() > (12.0f*12.0f)) {
		explSpeed = (explSpeed.Normalize() * 12.0f);
	}

	if (flags & PF_Shatter) {
		Shatter(piece, absPos, explSpeed);
		return;
	}

	if (pieces[piece]->original == NULL)
		return;

	// projectiles that don't fall could live forever
	int newflags = PF_Fall;

	const float partSat = projectileHandler->GetParticleSaturation();

	if (flags & PF_Explode) { newflags |= PF_Explode; }
	// if (flags & PF_Fall) { newflags |=  PF_Fall; }
	if ((flags & PF_Smoke) && partSat < 1.0f) { newflags |= PF_Smoke; }
	if ((flags & PF_Fire) && partSat < 0.95f) { newflags |= PF_Fire; }
	if (flags & PF_NoCEGTrail) { newflags |= PF_NoCEGTrail; }
	if (flags & PF_Recursive) { newflags |= PF_Recursive; }

	new CPieceProjectile(unit, pieces[piece], absPos, explSpeed, newflags, 0.5f);
#endif
}