コード例 #1
0
ファイル: missile.c プロジェクト: saniv/freecraft-ale-clone
/**
**	Work for missile hit.
*/
global void MissileHit(int missile)
{
    Unit* goal;

    // FIXME: should I move the PlayMissileSound to here?
    // FIXME: And should the the connected missile be defined in the missile
    // FIXME: structure

    switch( Missiles[missile].Type->Type ) {
    case MissileArrow:
    case MissileAxe:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        break;
    case MissileBallistaBolt:
    case MissileBigCannon:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        MakeMissile(MissileImpact
                    ,Missiles[missile].X
                    ,Missiles[missile].Y
                    ,0,0);
        break;

    case MissileSubmarineMissile:
    case MissileTurtleMissile:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        MakeMissile(MissileImpact
                    ,Missiles[missile].X
                    ,Missiles[missile].Y
                    ,0,0);
        break;

    case MissileGreenCross:
        break;
    }

    if( !Missiles[missile].SourceType ) {
        return;
    }

    // FIXME: must choose better goal!
    // FIXME: what can the missile hit?
    goal=UnitOnMapTile(Missiles[missile].X/TileSizeX
                       ,Missiles[missile].Y/TileSizeY);
    if( !goal || !goal->HP ) {
        return;
    }

    HitUnit(goal,CalculateDamage(Missiles[missile].SourceStats,goal));
}
コード例 #2
0
ファイル: missile.cpp プロジェクト: stefanhendriks/stratagus
/**
**  Handle point to point missile.
**
**  @param missile  Missile pointer.
**
**  @return         true if goal is reached, false else.
*/
bool PointToPointMissile(Missile &missile)
{
	if (MissileInitMove(missile) == true) {
		return true;
	}

	Assert(missile.Type != NULL);
	Assert(missile.TotalStep != 0);

	const PixelPos diff = (missile.destination - missile.source);
	missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;

	if (missile.Type->Smoke.Missile && (missile.CurrentStep || missile.State > 1)) {
		const PixelPos position = missile.position + missile.Type->size / 2;
		MakeMissile(*missile.Type->Smoke.Missile, position, position);
	}

	if (missile.Type->SmokeParticle && (missile.CurrentStep || missile.State > 1)) {
		const PixelPos position = missile.position + missile.Type->size / 2;
		missile.Type->SmokeParticle->pushPreamble();
		missile.Type->SmokeParticle->pushInteger(position.x);
		missile.Type->SmokeParticle->pushInteger(position.y);
		missile.Type->SmokeParticle->run();
	}

	if (missile.Type->Pierce) {
		MissileHandlePierce(missile, Map.MapPixelPosToTilePos(missile.position));
	}

	return false;
}
コード例 #3
0
ファイル: missile.c プロジェクト: saniv/freecraft-ale-clone
/**
**	Fire missile.
*/
global void FireMissile(Unit* unit)
{
    int x;
    int y;
    int dx;
    int dy;
    Unit* goal;
    Missile* missile;

    DebugLevel3("%s:\n",__FUNCTION__);

    if( unit->Type->MissileWeapon==MissileNone ) {
        // FIXME: must hit now!!!
        if( !(goal=unit->Command.Data.Move.Goal) ) {
            DebugLevel1("Missile-none hits no unit, shouldn't happen!\n");
            return;
        }

        // FIXME: make sure thats the correct unit.
        if( !goal->HP || goal->Command.Action==UnitActionDie ) {
            return;
        }

        HitUnit(goal,CalculateDamage(unit->Stats,goal));

        return;
    }

    x=unit->X*TileSizeX+TileSizeX/2;
    y=unit->Y*TileSizeY+TileSizeY/2;
    if( (goal=unit->Command.Data.Move.Goal) ) {
        // Fire to nearest point of unit!
        if( goal->Type ) {
            NearestOfUnit(goal,unit->X,unit->Y,&dx,&dy);
        } else {
            // FIXME: unit killed?
            dx=goal->X;
            dy=goal->Y;
        }
        DebugLevel3("Fire to unit at %d,%d\n",dx,dy);
        dx=dx*TileSizeX+TileSizeX/2;
        dy=dy*TileSizeY+TileSizeY/2;
    } else {
        dx=unit->Command.Data.Move.DX*TileSizeX+TileSizeX/2;
        dy=unit->Command.Data.Move.DY*TileSizeY+TileSizeY/2;
    }

    missile=MakeMissile(unit->Type->MissileWeapon,x,y,dx,dy);
    //
    //	Damage of missile
    //
    // missile->Damage=CalculateDamage(unit,goal);
    missile->SourceUnit=unit;
    missile->SourceType=unit->Type;
    missile->SourceStats=unit->Stats;
    missile->SourcePlayer=unit->Player;
}
コード例 #4
0
ファイル: script_missile.cpp プロジェクト: ajaykon/Stratagus
/**
**  Create a missile on the map
**
**  @param l  Lua state.
**
*/
static int CclCreateMissile(lua_State *l)
{
	LuaCheckArgs(l, 6);

	const std::string name = LuaToString(l, 1);
	const MissileType *mtype = MissileTypeByIdent(name);
	if (!mtype) {
		LuaError(l, "Bad missile");
	}
	PixelPos startpos, endpos;
	if (!lua_istable(l, 2) || lua_rawlen(l, 2) != 2) {
		LuaError(l, "incorrect argument !!");
	}
	lua_rawgeti(l, 2, 1);
	startpos.x = LuaToNumber(l, -1);
	lua_pop(l, 1);
	lua_rawgeti(l, 2, 2);
	startpos.y = LuaToNumber(l, -1);
	lua_pop(l, 1);
	if (!lua_istable(l, 3) || lua_rawlen(l, 3) != 2) {
		LuaError(l, "incorrect argument !!");
	}
	lua_rawgeti(l, 3, 1);
	endpos.x = LuaToNumber(l, -1);
	lua_pop(l, 1);
	lua_rawgeti(l, 3, 2);
	endpos.y = LuaToNumber(l, -1);
	lua_pop(l, 1);

	const int sourceUnitId = LuaToNumber(l, 4);
	const int destUnitId = LuaToNumber(l, 5);
	const bool dealDamage = LuaToBoolean(l, 6);
	CUnit *sourceUnit = sourceUnitId != -1 ? &UnitManager.GetSlotUnit(sourceUnitId) : NULL;
	CUnit *destUnit = destUnitId != -1 ? &UnitManager.GetSlotUnit(destUnitId) : NULL;

	if (sourceUnit != NULL) {
		startpos += sourceUnit->GetMapPixelPosTopLeft();
	}
	if (destUnit != NULL) {
		endpos += destUnit->GetMapPixelPosTopLeft();
	}

	Missile *missile = MakeMissile(*mtype, startpos, endpos);
	if (!missile) {
		return 0;
	}
	if (dealDamage) {
		missile->SourceUnit = sourceUnit;
	}
	missile->TargetUnit = destUnit;
	return 0;
}
コード例 #5
0
ファイル: script_missile.cpp プロジェクト: Andrettin/Wyrmgus
/**
**  Create a missile on the map
**
**  @param l  Lua state.
**
*/
static int CclCreateMissile(lua_State *l)
{
	const int arg = lua_gettop(l);
	if (arg < 6 || arg > 7) {
		LuaError(l, "incorrect argument");
	}

	const std::string name = LuaToString(l, 1);
	const MissileType *mtype = MissileTypeByIdent(name);
	if (!mtype) {
		LuaError(l, "Bad missile");
	}
	PixelPos startpos, endpos;
	CclGetPos(l, &startpos.x, &startpos.y, 2);
	CclGetPos(l, &endpos.x, &endpos.y, 3);

	const int sourceUnitId = LuaToNumber(l, 4);
	const int destUnitId = LuaToNumber(l, 5);
	const bool dealDamage = LuaToBoolean(l, 6);
	const bool mapRelative = arg == 7 ? LuaToBoolean(l, 7) : false;
	CUnit *sourceUnit = sourceUnitId != -1 ? &UnitManager.GetSlotUnit(sourceUnitId) : nullptr;
	CUnit *destUnit = destUnitId != -1 ? &UnitManager.GetSlotUnit(destUnitId) : nullptr;

	if (mapRelative == false) {
		if (sourceUnit != nullptr) {
			startpos += sourceUnit->GetMapPixelPosTopLeft();
		}
		if (destUnit != nullptr) {
			endpos += destUnit->GetMapPixelPosTopLeft();
		}
	}

	//Wyrmgus start
//	Missile *missile = MakeMissile(*mtype, startpos, endpos);
	Missile *missile = MakeMissile(*mtype, startpos, endpos, 0);
	//Wyrmgus end
	if (!missile) {
		return 0;
	}
	if (dealDamage) {
		missile->SourceUnit = sourceUnit;
	}
	missile->TargetUnit = destUnit;
	return 0;
}
コード例 #6
0
//Wyrmgus start
///* virtual */ int Spell_AreaBombardment::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
/* virtual */ int Spell_AreaBombardment::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos, int z)
//Wyrmgus end
{
	int fields = this->Fields;
	const int shards = this->Shards;
	const int damage = this->Damage;
	const PixelDiff offset(this->StartOffsetX, this->StartOffsetY);
	const MissileType *missile = this->Missile;

	while (fields--) {
		Vec2i dpos;

		// FIXME: radius configurable...
		do {
			// find new destination in the map
			dpos.x = goalPos.x + SyncRand() % 5 - 2;
			dpos.y = goalPos.y + SyncRand() % 5 - 2;
		//Wyrmgus start
//		} while (!Map.Info.IsPointOnMap(dpos));
		} while (!Map.Info.IsPointOnMap(dpos, z));
		//Wyrmgus end

		const PixelPos dest = Map.TilePosToMapPixelPos_Center(dpos);
		const PixelPos start = dest + offset;
		for (int i = 0; i < shards; ++i) {
			//Wyrmgus start
//			::Missile *mis = MakeMissile(*missile, start, dest);
			::Missile *mis = MakeMissile(*missile, start, dest, z);
			//Wyrmgus end
			if (mis->Type->BlizzardSpeed) {
				mis->Delay = i * mis->Type->Sleep * 2 * PixelTileSize.x / mis->Type->BlizzardSpeed;
			} else if (mis->Type->Speed) {
				mis->Delay = i * mis->Type->Sleep * 2 * PixelTileSize.x / mis->Type->Speed;
			} else {
				mis->Delay = i * mis->Type->Sleep * mis->Type->G->NumFrames;
			}
			mis->Damage = damage;
			// FIXME: not correct -- blizzard should continue even if mage is
			//    destroyed (though it will be quite short time...)
			mis->SourceUnit = &caster;
		}
	}
	return 1;
}
コード例 #7
0
ファイル: missile.cpp プロジェクト: OneSleepyDev/boswars_osd
/**
**  Calculate parabolic trajectories.
**
**  @param missile  Missile pointer.
**
**  @return         1 if target is reached, 0 otherwise
**
**  @todo Find good values for ZprojToX and Y
*/
static int ParabolicMissile(Missile *missile)
{
	int orig_x;   // position before moving.
	int orig_y;   // position before moving.
	int xstep;
	int ystep;
	int k;        // Coefficient of the parabol.
	int zprojToX; // Projection of Z axis on axis X.
	int zprojToY; // Projection of Z axis on axis Y.
	int z;        // should be missile->Z later.
	int x;
	int y;

	k = -2048; //-1024; // Should be initialised by an other method (computed with distance...)
	zprojToX = 4;
	zprojToY = 1024;
	if (MissileInitMove(missile) == 1) {
		return 1;
	}
	Assert(missile->Type != NULL);
	orig_x = missile->X;
	orig_y = missile->Y;
	xstep = missile->DX - missile->SourceX;
	ystep = missile->DY - missile->SourceY;
	Assert(missile->TotalStep != 0);
	xstep = xstep * 1000 / missile->TotalStep;
	ystep = ystep * 1000 / missile->TotalStep;
	missile->X = missile->SourceX + xstep * missile->CurrentStep / 1000;
	missile->Y = missile->SourceY + ystep * missile->CurrentStep / 1000;
	Assert(k != 0);
	z = missile->CurrentStep * (missile->TotalStep - missile->CurrentStep) / k;
	// Until Z is used for drawing, modify X and Y.
	missile->X += z * zprojToX / 64;
	missile->Y += z * zprojToY / 64;
	MissileNewHeadingFromXY(missile, missile->X - orig_x, missile->Y - orig_y);
	if (missile->Type->SmokeMissile && missile->CurrentStep) {
		x = missile->X + missile->Type->Width / 2;
		y = missile->Y + missile->Type->Height / 2;
		MakeMissile(missile->Type->SmokeMissile, x, y, x, y);
	}
	return 0;
}
コード例 #8
0
/**
**  Calculate parabolic trajectories.
**
**  @param missile  Missile pointer.
**
**  @return         1 if target is reached, 0 otherwise
**
**  @todo Find good values for ZprojToX and Y
*/
static int ParabolicMissile(Missile &missile)
{
	int k;        // Coefficient of the parabol.
	int zprojToX; // Projection of Z axis on axis X.
	int zprojToY; // Projection of Z axis on axis Y.
	int z;        // should be missile.Z later.

	k = -2048; //-1024; // Should be initialised by an other method (computed with distance...)
	zprojToX = 4;
	zprojToY = 1024;
	if (MissileInitMove(missile) == 1) {
		return 1;
	}
	Assert(missile.Type != NULL);
	const PixelPos orig_pos = missile.position;
	Assert(missile.TotalStep != 0);
	const PixelPos diff = (missile.destination - missile.source);
	missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;

	Assert(k != 0);
	z = missile.CurrentStep * (missile.TotalStep - missile.CurrentStep) / k;
	// Until Z is used for drawing, modify X and Y.
	missile.position.x += z * zprojToX / 64;
	missile.position.y += z * zprojToY / 64;
	missile.MissileNewHeadingFromXY(missile.position - orig_pos);
	if (missile.Type->Smoke.Missile && missile.CurrentStep) {
		const PixelPos position = missile.position + missile.Type->size / 2;
		MakeMissile(*missile.Type->Smoke.Missile, position, position);
	}
	if (missile.Type->SmokeParticle && missile.CurrentStep) {
		const PixelPos position = missile.position + missile.Type->size / 2;
		missile.Type->SmokeParticle->pushPreamble();
		missile.Type->SmokeParticle->pushInteger(position.x);
		missile.Type->SmokeParticle->pushInteger(position.y);
		missile.Type->SmokeParticle->run();
	}
	if (missile.Type->Pierce) {
		MissileHandlePierce(missile, Map.MapPixelPosToTilePos(missile.position));
	}
	return 0;
}
コード例 #9
0
ファイル: missile.cpp プロジェクト: OneSleepyDev/boswars_osd
/**
**  Handle point to point missile.
**
**  @param missile  Missile pointer.
**
**  @return         1 if goal is reached, 0 else.
*/
static int PointToPointMissile(Missile *missile)
{
	int xstep;
	int ystep;
	int x;
	int y;

	if (MissileInitMove(missile) == 1) {
		return 1;
	}

	Assert(missile->Type != NULL);
	Assert(missile->TotalStep != 0);
	xstep = (missile->DX - missile->SourceX) * 1024 / missile->TotalStep;
	ystep = (missile->DY - missile->SourceY) * 1024 / missile->TotalStep;
	missile->X = missile->SourceX + xstep * missile->CurrentStep / 1024;
	missile->Y = missile->SourceY + ystep * missile->CurrentStep / 1024;
	if (missile->Type->SmokeMissile && missile->CurrentStep) {
		x = missile->X + missile->Type->Width / 2;
		y = missile->Y + missile->Type->Height / 2;
		MakeMissile(missile->Type->SmokeMissile, x, y, x, y);
	}
	return 0;
}
コード例 #10
0
/**
**  Handle point to point missile.
**
**  @param missile  Missile pointer.
**
**  @return         true if goal is reached, false else.
*/
bool PointToPointMissile(Missile &missile)
{
	MissileInitMove(missile);
	if (missile.TotalStep == 0) {
		return true;
	}
	Assert(missile.Type != NULL);
	Assert(missile.TotalStep != 0);

	const PixelPos diff = (missile.destination - missile.source);
	const PixelPrecise sign(diff.x >= 0 ? 1.0 : -1.0, diff.y >= 0 ? 1.0 : -1.0); // Remember sign to move into correct direction
	const PixelPrecise oldPos((double)missile.position.x, (double)missile.position.y); // Remember old position
	PixelPrecise pos(oldPos);
	missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;

	for (; pos.x * sign.x <= missile.position.x * sign.x
		 && pos.y * sign.y <= missile.position.y * sign.y;
		 pos.x += (double)diff.x * missile.Type->SmokePrecision / missile.TotalStep,
		 pos.y += (double)diff.y * missile.Type->SmokePrecision / missile.TotalStep) {
		const PixelPos position((int)pos.x + missile.Type->size.x / 2,
								(int)pos.y + missile.Type->size.y / 2);

		if (missile.Type->Smoke.Missile && (missile.CurrentStep || missile.State > 1)) {
			Missile *smoke = MakeMissile(*missile.Type->Smoke.Missile, position, position);
			if (smoke && smoke->Type->NumDirections > 1) {
				smoke->MissileNewHeadingFromXY(diff);
			}
		}

		if (missile.Type->SmokeParticle && (missile.CurrentStep || missile.State > 1)) {
			missile.Type->SmokeParticle->pushPreamble();
			missile.Type->SmokeParticle->pushInteger(position.x);
			missile.Type->SmokeParticle->pushInteger(position.y);
			missile.Type->SmokeParticle->run();
		}

		if (missile.Type->Pierce) {
			const PixelPos posInt((int)pos.x, (int)pos.y);
			MissileHandlePierce(missile, Map.MapPixelPosToTilePos(posInt));
		}
	}

	// Handle wall blocking and kill first enemy
	for (pos = oldPos; pos.x * sign.x <= missile.position.x * sign.x
		 && pos.y * sign.y <= missile.position.y * sign.y;
		 pos.x += (double)diff.x / missile.TotalStep,
		 pos.y += (double)diff.y / missile.TotalStep) {
		const PixelPos position((int)pos.x + missile.Type->size.x / 2,
								(int)pos.y + missile.Type->size.y / 2);
		const Vec2i tilePos(Map.MapPixelPosToTilePos(position));

		if (Map.Info.IsPointOnMap(tilePos) && MissileHandleBlocking(missile, position)) {
			return true;
		}
		if (missile.Type->MissileStopFlags) {
			if (!Map.Info.IsPointOnMap(tilePos)) { // gone outside
				missile.TTL = 0;
				return false;
			}
			const CMapField &mf = *Map.Field(tilePos);
			if (missile.Type->MissileStopFlags & mf.Flags) { // incompatible terrain
				missile.position = position;
				missile.MissileHit();
				missile.TTL = 0;
				return false;
			}
		}
	}

	if (missile.CurrentStep == missile.TotalStep) {
		missile.position = missile.destination;
		return true;
	}
	return false;
}
コード例 #11
0
ファイル: script_missile.cpp プロジェクト: Andrettin/Wyrmgus
/**
**  Create a missile.
**
**  @param l  Lua state.
*/
static int CclMissile(lua_State *l)
{
	MissileType *type = nullptr;
	PixelPos position(-1, -1);
	PixelPos destination(-1, -1);
	PixelPos source(-1, -1);
	int z = 0;
	Missile *missile = nullptr;

	DebugPrint("FIXME: not finished\n");

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;

		if (!strcmp(value, "type")) {
			type = MissileTypeByIdent(LuaToString(l, j + 1));
		} else if (!strcmp(value, "pos")) {
			CclGetPos(l, &position.x, &position.y, j + 1);
		} else if (!strcmp(value, "origin-pos")) {
			CclGetPos(l, &source.x, &source.y, j + 1);
		} else if (!strcmp(value, "goal")) {
			CclGetPos(l, &destination.x, &destination.y, j + 1);
		//Wyrmgus start
		} else if (!strcmp(value, "map-layer")) {
			z = LuaToNumber(l, j + 1);
		//Wyrmgus end
		} else if (!strcmp(value, "local")) {
			Assert(type);
			//Wyrmgus start
//			missile = MakeLocalMissile(*type, position, destination);
			missile = MakeLocalMissile(*type, position, destination, z);
			//Wyrmgus end
			missile->Local = 1;
			--j;
		} else if (!strcmp(value, "global")) {
			Assert(type);
			//Wyrmgus start
//			missile = MakeMissile(*type, position, destination);
			missile = MakeMissile(*type, position, destination, z);
			//Wyrmgus end
			missile->position = position;
			missile->source = source;
			missile->destination = destination;
			//Wyrmgus start
			missile->MapLayer = z;
			//Wyrmgus end
			missile->Local = 0;
			--j;
		} else if (!strcmp(value, "frame")) {
			Assert(missile);
			missile->SpriteFrame = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "state")) {
			Assert(missile);
			missile->State = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "anim-wait")) {
			Assert(missile);
			missile->AnimWait = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "wait")) {
			Assert(missile);
			missile->Wait = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "delay")) {
			Assert(missile);
			missile->Delay = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "source")) {
			Assert(missile);
			lua_pushvalue(l, j + 1);
			missile->SourceUnit = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "target")) {
			Assert(missile);
			lua_pushvalue(l, j + 1);
			missile->TargetUnit = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "damage")) {
			Assert(missile);
			missile->Damage = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "lightning-damage")) {
			Assert(missile);
			missile->LightningDamage = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "ttl")) {
			Assert(missile);
			missile->TTL = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "hidden")) {
			Assert(missile);
			missile->Hidden = 1;
			--j;
		} else if (!strcmp(value, "step")) {
			Assert(missile);
			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
				LuaError(l, "incorrect argument");
			}
			missile->CurrentStep = LuaToNumber(l, j + 1, 1);
			missile->TotalStep = LuaToNumber(l, j + 1, 2);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}

	// we need to reinitialize position parameters - that's because of
	// the way InitMissile() (called from MakeLocalMissile()) computes
	// them - it works for creating a missile during a game but breaks
	// loading the missile from a file.
	missile->position = position;
	missile->source = source;
	missile->destination = destination;
	missile->MapLayer = z;
	return 0;
}
コード例 #12
0
ファイル: missile.cpp プロジェクト: Szunti/Wyrmgus
/**
**  Fire missile.
**
**  @param unit  Unit that fires the missile.
*/
void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos)
{
	Vec2i newgoalPos = goalPos;
	// Goal dead?
	if (goal) {
		Assert(!unit.Type->Missile.Missile->AlwaysFire || unit.Type->Missile.Missile->Range);
		if (goal->Destroyed) {
			DebugPrint("destroyed unit\n");
			return;
		}
		if (goal->Removed) {
			return;
		}
		if (goal->CurrentAction() == UnitActionDie) {
			if (unit.Type->Missile.Missile->AlwaysFire) {
				newgoalPos = goal->tilePos;
				goal = NULL;
			} else {
				return;
			}
		}
	}

	// No missile hits immediately!
	//Wyrmgus start
//	if (unit.Type->Missile.Missile->Class == MissileClassNone) {
	if (unit.Type->Missile.Missile->Class == MissileClassNone || (unit.Type->Animations && unit.Type->Animations->Attack && unit.Type->Animations->RangedAttack && ((goal && unit.MapDistanceTo(*goal) <= 1) || (!goal && unit.MapDistanceTo(goalPos) <= 1)) && !unit.Container)) { // treat melee attacks from units that have both attack and ranged attack animations as having missile class none
	//Wyrmgus end
		//Wyrmgus start
		int damage = 0;
		//Wyrmgus end
		// No goal, take target coordinates
		if (!goal) {
			if (Map.WallOnMap(goalPos)) {
				//Wyrmgus start
//				if (Map.HumanWallOnMap(goalPos)) {
				if (Map.HumanWallOnMap(goalPos) && CalculateHit(unit, *UnitTypeHumanWall->Stats, NULL) == true) {
				//Wyrmgus end
					//Wyrmgus start
					PlayUnitSound(unit, VoiceHit);
					damage = CalculateDamageStats(unit, *UnitTypeHumanWall->Stats, NULL);
					//Wyrmgus end
					Map.HitWall(goalPos,
								//Wyrmgus start
//								CalculateDamageStats(*unit.Stats,
//													 *UnitTypeHumanWall->Stats, unit.Variable[BLOODLUST_INDEX].Value));
								damage);
								//Wyrmgus end
				//Wyrmgus start
//				} else {
				} else if (Map.OrcWallOnMap(goalPos) && CalculateHit(unit, *UnitTypeOrcWall->Stats, NULL) == true) {
				//Wyrmgus end
					//Wyrmgus start
					PlayUnitSound(unit, VoiceHit);
					damage = CalculateDamageStats(unit, *UnitTypeOrcWall->Stats, NULL);
					//Wyrmgus end
					Map.HitWall(goalPos,
								//Wyrmgus start
//								CalculateDamageStats(*unit.Stats,
//													 *UnitTypeOrcWall->Stats, unit.Variable[BLOODLUST_INDEX].Value));
								damage);
								//Wyrmgus end
				}
				return;
			}
			DebugPrint("Missile-none hits no unit, shouldn't happen!\n");
			return;
		}
		//Wyrmgus start
//		HitUnit(&unit, *goal, CalculateDamage(unit, *goal, Damage));
		if (CalculateHit(unit, *goal->Stats, goal) == true) {
			damage = CalculateDamage(unit, *goal, Damage);
			HitUnit(&unit, *goal, damage);
			PlayUnitSound(unit, VoiceHit);
			
			//apply Thorns damage if attacker is at melee range
			if (goal && goal->Variable[THORNSDAMAGE_INDEX].Value && unit.MapDistanceTo(*goal) <= 1) {
				int thorns_damage = std::max<int>(goal->Variable[THORNSDAMAGE_INDEX].Value - unit.Variable[ARMOR_INDEX].Value, 1);
				if (GameSettings.NoRandomness) {
					thorns_damage -= ((thorns_damage + 2) / 2) / 2; //if no randomness setting is used, then the damage will always return what would have been the average damage with randomness
				} else {
					thorns_damage -= SyncRand() % ((thorns_damage + 2) / 2);
				}
				HitUnit(goal, unit, thorns_damage);
			}
		} else {
			PlayUnitSound(unit, VoiceMiss);
		}
		//Wyrmgus end
		return;
	}

	// If Firing from inside a Bunker
	CUnit *from = GetFirstContainer(unit);
	const int dir = ((unit.Direction + NextDirection / 2) & 0xFF) / NextDirection;
	const PixelPos startPixelPos = Map.TilePosToMapPixelPos_Center(from->tilePos)
								   + unit.Type->MissileOffsets[dir][0];

	Vec2i dpos;
	if (goal) {
		Assert(goal->Type);  // Target invalid?
		// Moved out of attack range?

		if (unit.MapDistanceTo(*goal) < unit.Type->MinAttackRange) {
			DebugPrint("Missile target too near %d,%d\n" _C_
					   unit.MapDistanceTo(*goal) _C_ unit.Type->MinAttackRange);
			// FIXME: do something other?
			return;
		}
		// Fire to nearest point of the unit!
		// If Firing from inside a Bunker
		if (unit.Container) {
			NearestOfUnit(*goal, GetFirstContainer(unit)->tilePos, &dpos);
		} else {
			dpos = goal->tilePos + goal->Type->GetHalfTileSize();
		}
	} else {
		dpos = newgoalPos;
		// FIXME: Can this be too near??
	}

	PixelPos destPixelPos = Map.TilePosToMapPixelPos_Center(dpos);
	Missile *missile = MakeMissile(*unit.Type->Missile.Missile, startPixelPos, destPixelPos);
	//
	// Damage of missile
	//
	if (goal) {
		missile->TargetUnit = goal;
	}
	missile->SourceUnit = &unit;
}
コード例 #13
0
ファイル: missile.cpp プロジェクト: OneSleepyDev/boswars_osd
/**
**  Fire missile.
**
**  @param unit  Unit that fires the missile.
*/
void FireMissile(CUnit *unit)
{
	int x;
	int y;
	int dx;
	int dy;
	CUnit *goal;
	Missile *missile;

	//
	// Goal dead?
	//
	goal = unit->Orders[0]->Goal;
	if (goal) {

		// Better let the caller/action handle this.

		if (goal->Destroyed) {
			DebugPrint("destroyed unit\n");
			return;
		}
		if (goal->Removed || goal->Orders[0]->Action == UnitActionDie) {
			return;
		}

		// FIXME: Some missile hit the field of the target and all units on it.
		// FIXME: goal is already dead, but missile could hit others?
	}

	//
	// No missile hits immediately!
	//
	if (unit->Type->Missile.Missile->Class == MissileClassNone) {
		// No goal, take target coordinates
		if (!goal) {
			DebugPrint("Missile-none hits no unit, shouldn't happen!\n");
			return;
		}

		HitUnit(unit, goal, CalculateDamage(unit, goal));

		return;
	}

	// If Firing from inside a Bunker
	if (unit->Container) {
		x = unit->Container->X * TileSizeX + TileSizeX / 2;  // missile starts in tile middle
		y = unit->Container->Y * TileSizeY + TileSizeY / 2;
	} else {
		x = unit->X * TileSizeX + TileSizeX / 2;  // missile starts in tile middle
		y = unit->Y * TileSizeY + TileSizeY / 2;
	}

	if (goal) {
		Assert(goal->Type);  // Target invalid?
		//
		// Moved out of attack range?
		//
		if (MapDistanceBetweenUnits(unit, goal) < unit->Type->MinAttackRange) {
			DebugPrint("Missile target too near %d,%d\n" _C_
				MapDistanceBetweenUnits(unit, goal) _C_ unit->Type->MinAttackRange);
			// FIXME: do something other?
			return;
		}
		// Fire to nearest point of the unit!
		// If Firing from inside a Bunker
		if (unit->Container) {
			NearestOfUnit(goal, unit->Container->X, unit->Container->Y, &dx, &dy);
		} else {
			NearestOfUnit(goal, unit->X, unit->Y, &dx, &dy);
		}
	} else {
		dx = unit->Orders[0]->X;
		dy = unit->Orders[0]->Y;
		// FIXME: Can this be too near??
	}

	// Fire to the tile center of the destination.
	dx = dx * TileSizeX + TileSizeX / 2;
	dy = dy * TileSizeY + TileSizeY / 2;
	missile = MakeMissile(unit->Type->Missile.Missile, x, y, dx, dy);
	//
	// Damage of missile
	//
	if (goal) {
		missile->TargetUnit = goal;
		goal->RefsIncrease();
	}
	missile->SourceUnit = unit;
	unit->RefsIncrease();
}
コード例 #14
0
ファイル: missile_parabolic.cpp プロジェクト: AMDmi3/Wyrmgus
/**
**  Calculate parabolic trajectories.
**
**  @param missile  Missile pointer.
**
**  @return         true if target is reached, false otherwise
**
**  @todo Find good values for ZprojToX and Y
*/
static bool ParabolicMissile(Missile &missile)
{
	// Should be initialised by an other method (computed with distance...)
	const double k = -missile.Type->ParabolCoefficient; // Coefficient of the parabol.
	const double zprojToX = 4.0;    // Projection of Z axis on axis X.
	const double zprojToY = 1024.0; // Projection of Z axis on axis Y.
	double z;        // should be missile.Z later.

	MissileInitMove(missile);
	if (missile.TotalStep == 0) {
		return true;
	}
	Assert(missile.Type != NULL);
	const PixelPos orig_pos = missile.position;
	Assert(missile.TotalStep != 0);
	const PixelPos diff = (missile.destination - missile.source);
	const PixelPrecise sign(diff.x >= 0 ? 1 : -1, diff.y >= 0 ? 1 : -1); // Remember sign to move into correct direction
	PixelPrecise pos(missile.position.x, missile.position.y); // Remember old position
	missile.position = missile.source + diff * missile.CurrentStep / missile.TotalStep;

	Assert(k != 0);
	z = (double)missile.CurrentStep * (missile.TotalStep - missile.CurrentStep) / k;
	// Until Z is used for drawing, modify X and Y.
	missile.position.x += (int)(z * zprojToX / 64.0);
	missile.position.y += (int)(z * zprojToY / 64.0);
	missile.MissileNewHeadingFromXY(missile.position - orig_pos);
	for (; pos.x * sign.x <= missile.position.x * sign.x
		 && pos.y * sign.y <= missile.position.y * sign.y;
		 pos.x += (double)diff.x * missile.Type->SmokePrecision / missile.TotalStep,
		 pos.y += (double)diff.y * missile.Type->SmokePrecision / missile.TotalStep) {

		if (missile.Type->Smoke.Missile && missile.CurrentStep) {
			const PixelPos position((int)pos.x + missile.Type->size.x / 2,
									(int)pos.y + missile.Type->size.y / 2);
			Missile *smoke = MakeMissile(*missile.Type->Smoke.Missile, position, position);
			if (smoke && smoke->Type->NumDirections > 1) {
				smoke->MissileNewHeadingFromXY(diff);
			}
		}

		if (missile.Type->SmokeParticle && missile.CurrentStep) {
			const PixelPos position((int)pos.x + missile.Type->size.x / 2,
									(int)pos.y + missile.Type->size.y / 2);
			missile.Type->SmokeParticle->pushPreamble();
			missile.Type->SmokeParticle->pushInteger(position.x);
			missile.Type->SmokeParticle->pushInteger(position.y);
			missile.Type->SmokeParticle->run();
		}

		if (missile.Type->Pierce) {
			const PixelPos position((int)pos.x, (int)pos.y);
			MissileHandlePierce(missile, Map.MapPixelPosToTilePos(position));
		}
	}

	if (missile.CurrentStep == missile.TotalStep) {
		missile.position = missile.destination;
		return true;
	}
	return false;
}
コード例 #15
0
ファイル: missile.c プロジェクト: saniv/freecraft-ale-clone
//FIXME: (Fabrice) I don't know if my update for missile visibility is fully
//correct.
global void MissileActions(void)
{
    int missile;

    for( missile=0; missile<NumMissiles; ++missile ) {
        if( Missiles[missile].Type==MissileFree ) {
            continue;
        }
        if( Missiles[missile].Wait-- ) {
            continue;
        }
        if (MissileVisible(missile)) {
            // check before movement
            MustRedraw|=RedrawMap;
        }
        switch( Missiles[missile].Type->Class ) {

        case MissileClassPointToPoint:
            Missiles[missile].Wait=1;
            if( PointToPointMissile(missile) ) {
                MissileHit(missile);
                Missiles[missile].Type=MissileFree;
            } else {
                //
                //	Animate missile, cycle through frames
                //
                Missiles[missile].Frame+=5;
                if( (Missiles[missile].Frame&127)
                        >=Missiles[missile].Type->RleSprite->NumFrames ) {
                    Missiles[missile].Frame=
                        // (Missiles[missile].Frame&128)|
                        (Missiles[missile].Frame
                         -Missiles[missile].Type->RleSprite
                         ->NumFrames);
                }
                DebugLevel3("Frame %d of %d\n"
                            ,Missiles[missile].Frame
                            ,Missiles[missile].Type->RleSprite->NumFrames);

            }
            break;

        case MissileClassPointToPointWithDelay:
            Missiles[missile].Wait=1;
            if( PointToPointMissile(missile) ) {
                switch( Missiles[missile].State++ ) {
                case 1:
                    // FIXME: bounces up.
                    PlayMissileSound(Missiles+missile,
                                     Missiles[missile].Type->ImpactSound.Sound);
                    // FIXME: make this configurable!!
                    switch( Missiles[missile].Type->Type ) {
                    case MissileSmallCannon:
                        MakeMissile(MissileCannonExplosion
                                    ,Missiles[missile].X
                                    ,Missiles[missile].Y
                                    ,0,0);
                        break;
                    case MissileBigCannon:
                        MakeMissile(MissileCannonTowerExplosion
                                    ,Missiles[missile].X
                                    ,Missiles[missile].Y
                                    ,0,0);
                        break;
                    case MissileCatapultRock:
                    case MissileBallistaBolt:
                        MakeMissile(MissileImpact
                                    ,Missiles[missile].X
                                    ,Missiles[missile].Y
                                    ,0,0);
                        break;
                    }
                    break;
                default:
                    MissileHit(missile);
                    Missiles[missile].Type=MissileFree;
                    break;
                }
            } else {
                //
                //	Animate missile, depends on the way.
                //
                // FIXME: how?
            }
            break;

        case MissileClassPointToPoint3Bounces:
            Missiles[missile].Wait=1;
            if( PointToPointMissile(missile) ) {
                //
                //	3 Bounces.
                //
                switch( Missiles[missile].State ) {
                case 1:
                case 3:
                case 5:
                    Missiles[missile].State+=2;
                    Missiles[missile].DX+=
                        Missiles[missile].Xstep*TileSizeX*2;
                    Missiles[missile].DY+=
                        Missiles[missile].Ystep*TileSizeY*2;
                    PlayMissileSound(Missiles+missile,
                                     Missiles[missile].Type->ImpactSound.Sound);
                    MakeMissile(MissileExplosion
                                ,Missiles[missile].X
                                ,Missiles[missile].Y
                                ,0,0);
                    MissileHit(missile);
                    // FIXME: hits to left and right
                    // FIXME: reduce damage
                    break;
                default:
                    Missiles[missile].Type=MissileFree;
                    break;
                }
            } else {
                //
                //	Animate missile, cycle through frames
                //
                Missiles[missile].Frame+=5;
                if( (Missiles[missile].Frame&127)
                        >=Missiles[missile].Type->RleSprite->NumFrames ) {
                    Missiles[missile].Frame=
                        // (Missiles[missile].Frame&128)|
                        (Missiles[missile].Frame
                         -Missiles[missile].Type->RleSprite
                         ->NumFrames);
                }
                DebugLevel3("Frame %d of %d\n"
                            ,Missiles[missile].Frame
                            ,Missiles[missile].Type->RleSprite->NumFrames);

            }
            break;

        case MissileClassPointToPointWithHit:
            Missiles[missile].Wait=1;
            if( PointToPointMissile(missile) ) {
                //
                //	Animate hit
                //
                Missiles[missile].Frame+=5;
                if( (Missiles[missile].Frame&127)
                        >=Missiles[missile].Type->RleSprite->NumFrames ) {
                    MissileHit(missile);
                    Missiles[missile].Type=MissileFree;
                }
            }
            break;

        case MissileClassStayWithDelay:
            Missiles[missile].Wait=1;
            if( ++Missiles[missile].Frame
                    ==Missiles[missile].Type->RleSprite
                    ->NumFrames ) {
                MissileHit(missile);
                Missiles[missile].Type=MissileFree;
            }
            break;

        case MissileClassCycleOnce:
            Missiles[missile].Wait=Missiles[missile].Type->Speed;
            switch( Missiles[missile].State ) {
            case 0:
            case 2:
                ++Missiles[missile].State;
                break;
            case 1:
                if( ++Missiles[missile].Frame
                        ==Missiles[missile].Type->RleSprite
                        ->NumFrames ) {
                    --Missiles[missile].Frame;
                    ++Missiles[missile].State;
                }
                break;
            case 3:
                if( !Missiles[missile].Frame-- ) {
                    MissileHit(missile);
                    Missiles[missile].Type=MissileFree;
                }
                break;
            }
            break;
        }
        if (Missiles[missile].Type!=MissileFree && MissileVisible(missile)) {
            // check after movement
            MustRedraw|=RedrawMap;
        }
    }
}
コード例 #16
0
ファイル: missile.cpp プロジェクト: stefanhendriks/stratagus
/**
**  Fire missile.
**
**  @param unit  Unit that fires the missile.
*/
void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos)
{
	Vec2i newgoalPos = goalPos;
	// Goal dead?
	if (goal) {
		Assert(!unit.Type->Missile.Missile->AlwaysFire || unit.Type->Missile.Missile->Range);
		if (goal->Destroyed) {
			DebugPrint("destroyed unit\n");
			return;
		}
		if (goal->Removed) {
			return;
		}
		if (goal->CurrentAction() == UnitActionDie) {
			if (unit.Type->Missile.Missile->AlwaysFire) {
				newgoalPos = goal->tilePos;
				goal = NULL;
			} else {
				return;
			}
		}
	}

	// No missile hits immediately!
	if (unit.Type->Missile.Missile->Class == MissileClassNone) {
		// No goal, take target coordinates
		if (!goal) {
			if (Map.WallOnMap(goalPos)) {
				if (Map.HumanWallOnMap(goalPos)) {
					Map.HitWall(goalPos,
								CalculateDamageStats(*unit.Stats,
													 *UnitTypeHumanWall->Stats, unit.Variable[BLOODLUST_INDEX].Value));
				} else {
					Map.HitWall(goalPos,
								CalculateDamageStats(*unit.Stats,
													 *UnitTypeOrcWall->Stats, unit.Variable[BLOODLUST_INDEX].Value));
				}
				return;
			}
			DebugPrint("Missile-none hits no unit, shouldn't happen!\n");
			return;
		}
		HitUnit(&unit, *goal, CalculateDamage(unit, *goal));
		return;
	}

	// If Firing from inside a Bunker
	CUnit *from = GetFirstContainer(unit);
	const int dir = ((unit.Direction + NextDirection / 2) & 0xFF) / NextDirection;
	const PixelPos startPixelPos = Map.TilePosToMapPixelPos_Center(from->tilePos)
								   + unit.Type->MissileOffsets[dir][0];

	Vec2i dpos;
	if (goal) {
		Assert(goal->Type);  // Target invalid?
		// Moved out of attack range?

		if (unit.MapDistanceTo(*goal) < unit.Type->MinAttackRange) {
			DebugPrint("Missile target too near %d,%d\n" _C_
					   unit.MapDistanceTo(*goal) _C_ unit.Type->MinAttackRange);
			// FIXME: do something other?
			return;
		}
		// Fire to nearest point of the unit!
		// If Firing from inside a Bunker
		if (unit.Container) {
			NearestOfUnit(*goal, GetFirstContainer(unit)->tilePos, &dpos);
		} else {
			dpos = goal->tilePos + goal->Type->GetHalfTileSize();
		}
	} else {
		dpos = newgoalPos;
		// FIXME: Can this be too near??
	}

	PixelPos destPixelPos = Map.TilePosToMapPixelPos_Center(dpos);
	Missile *missile = MakeMissile(*unit.Type->Missile.Missile, startPixelPos, destPixelPos);
	//
	// Damage of missile
	//
	if (goal) {
		missile->TargetUnit = goal;
	}
	missile->SourceUnit = &unit;
}
コード例 #17
0
ファイル: missile.cpp プロジェクト: OneSleepyDev/boswars_osd
/**
**  Work for missile hit.
**
**  @param missile  Missile reaching end-point.
*/
void MissileHit(Missile *missile)
{
	CUnit *goal;
	int x;
	int y;
	CUnit *table[UnitMax];
	int n;
	int i;
	int splash;

	if (missile->Type->ImpactSound.Sound) {
		PlayMissileSound(missile, missile->Type->ImpactSound.Sound);
	}

	x = missile->X + missile->Type->Width / 2;
	y = missile->Y + missile->Type->Height / 2;

	//
	// The impact generates a new missile.
	//
	if (missile->Type->ImpactMissile) {
		MakeMissile(missile->Type->ImpactMissile, x, y, x, y);
	}
	if (missile->Type->ImpactParticle) {
		missile->Type->ImpactParticle->pushPreamble();
		missile->Type->ImpactParticle->pushInteger(x);
		missile->Type->ImpactParticle->pushInteger(y);
		missile->Type->ImpactParticle->run();
	}

	if (!missile->SourceUnit) {  // no owner - green-cross ...
		return;
	}

	x /= TileSizeX;
	y /= TileSizeY;

	if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) {
		// FIXME: this should handled by caller?
		DebugPrint("Missile gone outside of map!\n");
		return;  // outside the map.
	}

	//
	// Choose correct goal.
	//
	if (!missile->Type->Range) {
		if (missile->TargetUnit) {
			//
			// Missiles without range only hits the goal always.
			//
			goal = missile->TargetUnit;
			if (goal->Destroyed) {  // Destroyed
				goal->RefsDecrease();
				missile->TargetUnit = NoUnitP;
				return;
			}
			MissileHitsGoal(missile, goal, 1);
			return;
		}
		return;
	}

	//
	// Hits all units in range.
	//
	i = missile->Type->Range;
	n = UnitCache.Select(x - i + 1, y - i + 1, x + i, y + i, table, UnitMax);
	Assert(missile->SourceUnit != NULL);
	for (i = 0; i < n; ++i) {
		goal = table[i];
		//
		// Can the unit attack the this unit-type?
		// NOTE: perhaps this should be come a property of the missile.
		//
		if (CanTarget(missile->SourceUnit->Type, goal->Type)) {
			splash = MapDistanceToUnit(x, y, goal);
			if (splash) {
				splash *= missile->Type->SplashFactor;
			} else {
				splash = 1;
			}
			MissileHitsGoal(missile, goal, splash);
		}
	}
}
コード例 #18
0
ファイル: missile.cpp プロジェクト: stefanhendriks/stratagus
/**
**  Work for missile hit.
*/
void Missile::MissileHit(CUnit *unit)
{
	const MissileType &mtype = *this->Type;

	if (mtype.ImpactSound.Sound) {
		PlayMissileSound(*this, mtype.ImpactSound.Sound);
	}
	const PixelPos pixelPos = this->position + this->Type->size / 2;

	//
	// The impact generates a new missile.
	//
	if (mtype.Impact.empty() == false) {
		for (std::vector<MissileConfig *>::const_iterator it = mtype.Impact.begin(); it != mtype.Impact.end(); ++it) {
			const MissileConfig &mc = **it;
			Missile *impact = MakeMissile(*mc.Missile, pixelPos, pixelPos);
			if (impact && impact->Type->Damage) {
				impact->SourceUnit = this->SourceUnit;
			}
		}
	}
	if (mtype.ImpactParticle) {
		mtype.ImpactParticle->pushPreamble();
		mtype.ImpactParticle->pushInteger(pixelPos.x);
		mtype.ImpactParticle->pushInteger(pixelPos.y);
		mtype.ImpactParticle->run();
	}

	if (!this->SourceUnit) {  // no owner - green-cross ...
		return;
	}

	const Vec2i pos = Map.MapPixelPosToTilePos(pixelPos);

	if (!Map.Info.IsPointOnMap(pos)) {
		// FIXME: this should handled by caller?
		DebugPrint("Missile gone outside of map!\n");
		return;  // outside the map.
	}

	//
	// Choose correct goal.
	//
	if (unit) {
		if (unit->Destroyed) {
			return;
		}
		if (mtype.Pierce && mtype.PierceOnce) {
			if (IsPiercedUnit(*this, *unit)) {
				return;
			} else {
				PiercedUnits.insert(this->PiercedUnits.begin(), unit);
			}
		}
		MissileHitsGoal(*this, *unit, 1);
		return;
	}
	if (!mtype.Range) {
		if (this->TargetUnit && (mtype.FriendlyFire == false
								 || this->TargetUnit->Player->Index != this->SourceUnit->Player->Index)) {
			//
			// Missiles without range only hits the goal always.
			//
			CUnit &goal = *this->TargetUnit;
			if (mtype.Pierce && mtype.PierceOnce) {
				if (IsPiercedUnit(*this, goal)) {
					return;
				} else {
					PiercedUnits.insert(this->PiercedUnits.begin(), &goal);
				}
			}
			if (goal.Destroyed) {
				this->TargetUnit = NULL;
				return;
			}
			MissileHitsGoal(*this, goal, 1);
			return;
		}
		MissileHitsWall(*this, pos, 1);
		return;
	}

	{
		//
		// Hits all units in range.
		//
		const Vec2i range(mtype.Range - 1, mtype.Range - 1);
		std::vector<CUnit *> table;
		Select(pos - range, pos + range, table);
		Assert(this->SourceUnit != NULL);
		for (size_t i = 0; i != table.size(); ++i) {
			CUnit &goal = *table[i];
			//
			// Can the unit attack this unit-type?
			// NOTE: perhaps this should be come a property of the missile.
			// Also check CorrectSphashDamage so land explosions can't hit the air units
			//
			if (CanTarget(*this->SourceUnit->Type, *goal.Type)
				&& (mtype.FriendlyFire == false || goal.Player->Index != this->SourceUnit->Player->Index)) {
				bool shouldHit = true;

				if (mtype.Pierce && mtype.PierceOnce) {
					if (IsPiercedUnit(*this, goal)) {
						shouldHit = false;
					} else {
						PiercedUnits.insert(this->PiercedUnits.begin(), &goal);
					}
				}

				if (mtype.CorrectSphashDamage == true) {
					bool isPositionSpell = false;
					if (this->TargetUnit == NULL && this->SourceUnit->CurrentAction() == UnitActionSpellCast) {
						const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(this->SourceUnit->CurrentOrder());
						if (order.GetSpell().Target == TargetPosition) {
							isPositionSpell = true;
						}
					}
					if (isPositionSpell || this->SourceUnit->CurrentAction() == UnitActionAttackGround) {
						if (goal.Type->UnitType != this->SourceUnit->Type->UnitType) {
							shouldHit = false;
						}
					} else {
						if (this->TargetUnit == NULL || goal.Type->UnitType != this->TargetUnit->Type->UnitType) {
							shouldHit = false;
						}
					}
				}
				if (shouldHit) {
					int splash = goal.MapDistanceTo(pos);

					if (splash) {
						splash *= mtype.SplashFactor;
					} else {
						splash = 1;
					}
					MissileHitsGoal(*this, goal, splash);
				}
			}
		}
	}

	// Missile hits ground.
	const Vec2i offset(mtype.Range, mtype.Range);
	const Vec2i posmin = pos - offset;
	for (int i = mtype.Range * 2; --i;) {
		for (int j = mtype.Range * 2; --j;) {
			const Vec2i posIt(posmin.x + i, posmin.y + j);

			if (Map.Info.IsPointOnMap(posIt)) {
				int d = Distance(pos, posIt);
				d *= mtype.SplashFactor;
				if (d == 0) {
					d = 1;
				}
				MissileHitsWall(*this, posIt, d);
			}
		}
	}
}
コード例 #19
0
/* virtual */ void CAnimation_SpawnMissile::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
	Assert(unit.Anim.Anim == this);

	const int startx = ParseAnimInt(&unit, this->startXStr.c_str());
	const int starty = ParseAnimInt(&unit, this->startYStr.c_str());
	const int destx = ParseAnimInt(&unit, this->destXStr.c_str());
	const int desty = ParseAnimInt(&unit, this->destYStr.c_str());
	const int flags = ParseAnimFlags(unit, this->flagsStr.c_str());
	const int offsetnum = ParseAnimInt(&unit, this->offsetNumStr.c_str());
	const CUnit *goal = flags & ANIM_SM_RELTARGET ? unit.CurrentOrder()->GetGoal() : &unit;
	const int dir = ((goal->Direction + NextDirection / 2) & 0xFF) / NextDirection;
	const PixelPos moff = goal->Type->MissileOffsets[dir][!offsetnum ? 0 : offsetnum - 1];
	PixelPos start;
	PixelPos dest;
	MissileType *mtype = MissileTypeByIdent(this->missileTypeStr);
	if (mtype == NULL) {
		return;
	}

	if (!goal || goal->Destroyed) {
		return;
	}
	if ((flags & ANIM_SM_PIXEL)) {
		start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + moff.x + startx;
		start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + moff.y + starty;
	} else {
		start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2 + moff.x;
		start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2 + moff.y;
	}
	if ((flags & ANIM_SM_TOTARGET)) {
		CUnit *target = goal->CurrentOrder()->GetGoal();
		if (!target || target->Destroyed) {
			Assert(!mtype->AlwaysFire || mtype->Range);
			if (!target && mtype->AlwaysFire == false) {
				return;
			}
		}
		if (!target) {
			if (goal->CurrentAction() == UnitActionAttack || goal->CurrentAction() == UnitActionAttackGround) {
				COrder_Attack &order = *static_cast<COrder_Attack *>(goal->CurrentOrder());
				dest = Map.TilePosToMapPixelPos_Center(order.GetGoalPos());
			} else if (goal->CurrentAction() == UnitActionSpellCast) {
				COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
				dest = Map.TilePosToMapPixelPos_Center(order.GetGoalPos());
			}
			if (flags & ANIM_SM_PIXEL) {
				dest.x += destx;
				dest.y += desty;
			} else {
				dest.x += destx * PixelTileSize.x;
				dest.y += desty * PixelTileSize.y;
			}
		} else if (flags & ANIM_SM_PIXEL) {
			dest.x = target->GetMapPixelPosCenter().x + destx;
			dest.y = target->GetMapPixelPosCenter().y + desty;
		} else {
			dest.x = (target->tilePos.x + destx) * PixelTileSize.x;
			dest.y = (target->tilePos.y + desty) * PixelTileSize.y;
			dest += target->Type->GetPixelSize() / 2;
		}
	} else {
		if ((flags & ANIM_SM_PIXEL)) {
			dest.x = goal->GetMapPixelPosCenter().x + destx;
			dest.y = goal->GetMapPixelPosCenter().y + desty;
		} else {
			dest.x = (goal->tilePos.x + destx) * PixelTileSize.x;
			dest.y = (goal->tilePos.y + desty) * PixelTileSize.y;
			dest += goal->Type->GetPixelSize() / 2;
		}
	}
	Vec2i destTilePos = Map.MapPixelPosToTilePos(dest);
	const int dist = goal->MapDistanceTo(destTilePos);
	if ((flags & ANIM_SM_RANGED) && !(flags & ANIM_SM_PIXEL)
		&& dist > goal->Stats->Variables[ATTACKRANGE_INDEX].Max
		&& dist < goal->Type->MinAttackRange) {
	} else {
		Missile *missile = MakeMissile(*mtype, start, dest);
		if (flags & ANIM_SM_SETDIRECTION) {
			PixelPos posd;
			posd.x = Heading2X[goal->Direction / NextDirection];
			posd.y = Heading2Y[goal->Direction / NextDirection];
			missile->MissileNewHeadingFromXY(posd);
		}
		if (flags & ANIM_SM_DAMAGE) {
			missile->SourceUnit = &unit;
		}
		if (flags & ANIM_SM_TOTARGET) {
			missile->TargetUnit = goal->CurrentOrder()->GetGoal();
		}
	}
}