Add catapult to enemy spawn

Also fix some catapult behavior (such as pushing it along waypoints)
alut-include-path
Sven Eberhardt 2017-02-26 19:16:26 -05:00
parent aa5f5cd654
commit 1ff3b17dad
6 changed files with 103 additions and 40 deletions

View File

@ -56,6 +56,7 @@ local SingleWeaponAttackMode = {
{
weapon->~SetStackCount(1); // Ensure departure is called on every object
weapon.Departure = AI.Departure_WeaponRespawn;
fx.has_ammo_respawn = true;
}
}
},

View File

@ -92,6 +92,9 @@ public func ExecuteJump(effect fx)
// Follow attack path or return to the AI's home if not yet there.
public func ExecuteIdle(effect fx)
{
// Persist commands because constant command resets may hinder execution
if (fx.Target->GetCommand() && Random(4)) return true;
// Follow attack path
if (fx.attack_path)
{
var next_pt = fx.attack_path[0];
@ -111,30 +114,38 @@ public func ExecuteIdle(effect fx)
fx.home_y = next_pt.Y;
fx.home_dir = Random(2);
}
if (!Inside(fx.Target->GetX() - fx.home_x, -5, 5) || !Inside(fx.Target->GetY() - fx.home_y, -15, 15))
// Check if we need to move/push to a target
if (fx.vehicle)
{
return fx.Target->SetCommand("MoveTo", nil, fx.home_x, fx.home_y);
if (!Inside(fx.vehicle->GetX() - fx.home_x, -15, 15) || !Inside(fx.vehicle->GetY() - fx.home_y, -20, 20))
{
return fx.Target->SetCommand("PushTo", fx.vehicle, fx.home_x, fx.home_y);
}
}
else
{
// Next section on path or done?
if (fx.attack_path)
if (!Inside(fx.Target->GetX() - fx.home_x, -5, 5) || !Inside(fx.Target->GetY() - fx.home_y, -15, 15))
{
if (GetLength(fx.attack_path) > 1)
{
fx.attack_path = fx.attack_path[1:];
// Wait one cycle. After that, ExecuteIdle will continue the path.
}
else
{
fx.attack_path = nil;
}
return fx.Target->SetCommand("MoveTo", nil, fx.home_x, fx.home_y);
}
// Movement done (for now)
fx.Target->SetCommand("None");
fx.Target->SetComDir(COMD_Stop);
fx.Target->SetDir(fx.home_dir);
}
// Next section on path or done?
if (fx.attack_path)
{
if (GetLength(fx.attack_path) > 1)
{
fx.attack_path = fx.attack_path[1:];
// Wait one cycle. After that, ExecuteIdle will continue the path.
}
else
{
fx.attack_path = nil;
}
}
// Movement done (for now)
fx.Target->SetCommand("None");
fx.Target->SetComDir(COMD_Stop);
fx.Target->SetDir(fx.home_dir);
// Nothing to do.
return false;
}

View File

@ -218,6 +218,18 @@ public func SetAttackPath(object clonk, array new_attack_path)
return true;
}
// Set controlled vehicle
public func SetVehicle(object clonk, object new_vehicle)
{
if (GetType(this) != C4V_Def)
Log("WARNING: SetVehicle(%v, %v) not called from definition context but from %v", clonk, new_vehicle, this);
var fx_ai = GetAI(clonk);
if (!fx_ai)
return false;
fx_ai.vehicle = new_vehicle;
return true;
}
/*-- AI Effect --*/
@ -508,22 +520,7 @@ public func ExecuteArm(effect fx)
{
// Find shield.
fx.shield = fx.Target->FindContents(Shield);
// Find a weapon. Depends on attack mode
if (Call(fx.attack_mode.FindWeapon, fx))
{
// Select unless it's e.g. a vehicle or a spell
SelectItem(fx, fx.weapon);
return true;
}
// No weapon.
return false;
}
public func FindInventoryWeapon(effect fx)
{
fx.ammo_check = nil;
fx.ranged = false;
// Find weapon in inventory, mark it as equipped and set according strategy, etc.
// Vehicle control overrides all other weapons
if (fx.weapon = fx.vehicle)
{
if (this->CheckVehicleAmmo(fx, fx.weapon))
@ -537,6 +534,22 @@ public func FindInventoryWeapon(effect fx)
else
fx.weapon = nil;
}
// Find a weapon. Depends on attack mode
if (Call(fx.attack_mode.FindWeapon, fx))
{
// Select unless it's e.g. a vehicle or a spell
SelectItem(fx, fx.weapon);
return true;
}
// No weapon.
return false;
}
public func FindInventoryWeapon(effect fx)
{
// Find weapon in inventory, mark it as equipped and set according strategy, etc.
fx.ammo_check = nil;
fx.ranged = false;
if (FindInventoryWeaponGrenadeLauncher(fx)) return true;
if (FindInventoryWeaponBlunderbuss(fx)) return true;
if (FindInventoryWeaponBow(fx)) return true;

View File

@ -103,15 +103,20 @@ private func ExecuteCatapult(effect fx)
// Can shoot now?
if (fx.time >= fx.aim_time + fx.aim_wait && PathFree(x, y - 20, x + dx, y + dy - 20))
{
fx.aim_weapon->~DoFire(fx.Target, power, 0);
fx.aim_weapon = nil;
// Need to wait for ammo?
if (fx.vehicle->ContentsCount() || fx.Target->ContentsCount())
{
fx.aim_weapon->~DoFire(fx.Target, power, 0);
fx.aim_weapon = nil;
}
}
return true;
}
private func CheckCatapultAmmo(effect fx, object vehicle)
{
return vehicle->ContentsCount() > 0;
// Must have ammo in the catapult or in the clonk (or be respawning ammo)
return vehicle->ContentsCount() > 0 || fx.Target->ContentsCount() > 0 || fx.has_ammo_respawn;
}

View File

@ -539,18 +539,18 @@ public func GetAIClonkEditorProps()
return this.AIClonkEditorProps;
}
public func GetAIClonkDefaultPropValues()
public func GetAIClonkDefaultPropValues(string attack_mode)
{
// Default settings for AI enemy clonks
return {
AttackMode = { Identifier="Sword" },
AttackMode = { Identifier=attack_mode ?? "Sword" },
Color = 0xff0000,
Bounty = 0,
ScaleX = 100,
ScaleY = 100,
Speed = 100,
Energy = 50,
Backpack = true,
Backpack = false,
};
}

View File

@ -314,13 +314,46 @@ public func CatapultDismount(object clonk)
return true;
}
/*-- Properties --*/
/* Register enemy spawn with catapult */
func Definition(proplist def)
{
def.PictureTransformation = Trans_Mul(Trans_Translate(-1000, -4000, 0), Trans_Rotate(-20, 1, 0, 0), Trans_Rotate(35, 0, 1, 0));
EnemySpawn->AddEnemyDef("Catapult",
{ SpawnType=Catapult,
SpawnFunction=def.SpawnCatapult,
OffsetAttackPathByPos=false,
GetInfoString=def.GetSpawnInfoString },
EnemySpawn->GetAIClonkDefaultPropValues("Firestone"),
EnemySpawn->GetAIClonkEditorProps());
}
private func SpawnCatapult(array pos, proplist clonk_data, proplist enemy_def, array clonk_attack_path, object spawner)
{
// First spawn the catapult
var catapult = CreateObjectAbove(Catapult, pos[0], pos[1], g_enemyspawn_player);
catapult->Unstick(10);
if (!catapult) return;
// Next let a clonk steer the catapult
var clonk = EnemySpawn->SpawnClonk(pos, clonk_data, enemy_def, clonk_attack_path, spawner);
if (!clonk) return;
clonk->SetAction("Push", catapult);
// Set attack mode
AI->SetVehicle(clonk, catapult);
// Only the clonk is an actual enemy
return clonk;
}
private func GetSpawnInfoString(proplist enemy_data)
{
// Prepend balloon to clonk info string
return Format("{{Catapult}}%s", EnemySpawn->GetAIClonkInfoString(enemy_data));
}
/* Properties */
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 1;