forked from Mirrors/openclonk
parent
06cd643d15
commit
3d1caffcf6
|
@ -1,46 +1,46 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<!DOCTYPE funcs
|
<!DOCTYPE funcs
|
||||||
SYSTEM '../../../clonk.dtd'>
|
SYSTEM '../../../clonk.dtd'>
|
||||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||||
<funcs>
|
<funcs>
|
||||||
<func>
|
<func>
|
||||||
<title>CanInsertMaterial</title>
|
<title>CanInsertMaterial</title>
|
||||||
<category>Landscape</category>
|
<category>Landscape</category>
|
||||||
<subcat>Material</subcat>
|
<subcat>Material</subcat>
|
||||||
<version>5.4 OC</version>
|
<version>5.4 OC</version>
|
||||||
<syntax>
|
<syntax>
|
||||||
<rtype>bool</rtype>
|
<rtype>bool</rtype>
|
||||||
<params>
|
<params>
|
||||||
<param>
|
<param>
|
||||||
<type>int</type>
|
<type>int</type>
|
||||||
<name>material_index</name>
|
<name>material_index</name>
|
||||||
<desc>Material to test to be inserted (see <funclink>Material</funclink>()).</desc>
|
<desc>Material to test to be inserted (see <funclink>Material</funclink>()).</desc>
|
||||||
</param>
|
</param>
|
||||||
<param>
|
<param>
|
||||||
<type>int</type>
|
<type>int</type>
|
||||||
<name>x</name>
|
<name>x</name>
|
||||||
<desc>X insert position or offset</desc>
|
<desc>X insert position or offset</desc>
|
||||||
<optional />
|
<optional />
|
||||||
</param>
|
</param>
|
||||||
<param>
|
<param>
|
||||||
<type>int</type>
|
<type>int</type>
|
||||||
<name>y</name>
|
<name>y</name>
|
||||||
<desc>Y insert position or offset</desc>
|
<desc>Y insert position or offset</desc>
|
||||||
<optional />
|
<optional />
|
||||||
</param>
|
</param>
|
||||||
<param>
|
<param>
|
||||||
<type>proplist</type>
|
<type>proplist</type>
|
||||||
<name>out_insertpos</name>
|
<name>out_insertpos</name>
|
||||||
<desc>If a writeable proplist is passed, members x and y are filled with the position at which the material would be inserted.</desc>
|
<desc>If a writeable proplist is passed, members x and y are filled with the position at which the material would be inserted.</desc>
|
||||||
<optional />
|
<optional />
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</syntax>
|
</syntax>
|
||||||
<desc>Tests if a material pixel at the given position can be inserted.</desc>
|
<desc>Tests if a material pixel at the given position can be inserted.</desc>
|
||||||
<remark>If the target position already contains material of the same density as the inserted material, the engine will search upwards for a proper insertion position.</remark>
|
<remark>If the target position already contains material of the same density as the inserted material, the engine will search upwards for a proper insertion position.</remark>
|
||||||
<related>
|
<related>
|
||||||
<funclink>Material</funclink>
|
<funclink>Material</funclink>
|
||||||
</related>
|
</related>
|
||||||
</func>
|
</func>
|
||||||
<author>Sven2</author><date>2001-11</date>
|
<author>Sven2</author><date>2001-11</date>
|
||||||
</funcs>
|
</funcs>
|
||||||
|
|
|
@ -1,215 +1,215 @@
|
||||||
#include AI
|
#include AI
|
||||||
|
|
||||||
public func SetEnemyData(object clonk, proplist data)
|
public func SetEnemyData(object clonk, proplist data)
|
||||||
{
|
{
|
||||||
var fx = clonk->~GetAI();
|
var fx = clonk->~GetAI();
|
||||||
if (fx)
|
if (fx)
|
||||||
{
|
{
|
||||||
if (data.Siege)
|
if (data.Siege)
|
||||||
fx.is_siege = true;
|
fx.is_siege = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public func FindTarget(effect fx)
|
public func FindTarget(effect fx)
|
||||||
{
|
{
|
||||||
// Attack doors and statue unless an enemy clonk is closer than these objectives
|
// Attack doors and statue unless an enemy clonk is closer than these objectives
|
||||||
var objective;
|
var objective;
|
||||||
if (g_doorleft && fx.Target->GetX() <= g_doorleft->GetX() + 5)
|
if (g_doorleft && fx.Target->GetX() <= g_doorleft->GetX() + 5)
|
||||||
objective = g_doorleft.dummy_target;
|
objective = g_doorleft.dummy_target;
|
||||||
else if (g_doorright && fx.Target->GetX() >= g_doorright->GetX()-5)
|
else if (g_doorright && fx.Target->GetX() >= g_doorright->GetX()-5)
|
||||||
objective = g_doorright.dummy_target;
|
objective = g_doorright.dummy_target;
|
||||||
else
|
else
|
||||||
objective = g_statue;
|
objective = g_statue;
|
||||||
var target = inherited(fx, ...);
|
var target = inherited(fx, ...);
|
||||||
if (objective)
|
if (objective)
|
||||||
if (fx.is_siege || !target || fx.Target->ObjectDistance(target) > fx.Target->ObjectDistance(objective))
|
if (fx.is_siege || !target || fx.Target->ObjectDistance(target) > fx.Target->ObjectDistance(objective))
|
||||||
target = objective;
|
target = objective;
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
private func CheckVehicleAmmo(effect fx, object catapult)
|
private func CheckVehicleAmmo(effect fx, object catapult)
|
||||||
{
|
{
|
||||||
// Ammo is auto-refilled
|
// Ammo is auto-refilled
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private func ExecuteBomber(effect fx)
|
private func ExecuteBomber(effect fx)
|
||||||
{
|
{
|
||||||
// Still carrying the bomb?
|
// Still carrying the bomb?
|
||||||
if (fx.weapon->Contained() != fx.Target)
|
if (fx.weapon->Contained() != fx.Target)
|
||||||
{
|
{
|
||||||
fx.weapon=nil;
|
fx.weapon=nil;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Are we in range?
|
// Are we in range?
|
||||||
if (fx.Target->ObjectDistance(fx.target) < 20)
|
if (fx.Target->ObjectDistance(fx.target) < 20)
|
||||||
{
|
{
|
||||||
// Suicide!
|
// Suicide!
|
||||||
fx.weapon->GoBoom();
|
fx.weapon->GoBoom();
|
||||||
fx.Target->Kill();
|
fx.Target->Kill();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not in range. Walk there.
|
// Not in range. Walk there.
|
||||||
if (!fx.Target->GetCommand() || !Random(10))
|
if (!fx.Target->GetCommand() || !Random(10))
|
||||||
fx.Target->SetCommand("MoveTo", fx.target);
|
fx.Target->SetCommand("MoveTo", fx.target);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute(effect fx, int time)
|
func Execute(effect fx, int time)
|
||||||
{
|
{
|
||||||
// Execution: No defensive AI. All enemies move towards target
|
// Execution: No defensive AI. All enemies move towards target
|
||||||
var target = fx.target ?? g_statue;
|
var target = fx.target ?? g_statue;
|
||||||
if (!Random(10) && target)
|
if (!Random(10) && target)
|
||||||
{
|
{
|
||||||
var tx = target->GetX();
|
var tx = target->GetX();
|
||||||
if (Abs(tx-fx.Target->GetX())>30)
|
if (Abs(tx-fx.Target->GetX())>30)
|
||||||
{
|
{
|
||||||
fx.Target->SetCommand("MoveTo", nil, BoundBy(fx.Target->GetX(), tx - 30, tx + 30), target->GetY());
|
fx.Target->SetCommand("MoveTo", nil, BoundBy(fx.Target->GetX(), tx - 30, tx + 30), target->GetY());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return inherited(fx, time, ...);
|
return inherited(fx, time, ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteIdle(effect fx)
|
func ExecuteIdle(effect fx)
|
||||||
{
|
{
|
||||||
// Idle execution overridden by Execute
|
// Idle execution overridden by Execute
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
/* Enemy creation */
|
/* Enemy creation */
|
||||||
|
|
||||||
func Departure_WeaponRespawn(object container)
|
func Departure_WeaponRespawn(object container)
|
||||||
{
|
{
|
||||||
// Weapon used? Schedule to respawn a new one!
|
// Weapon used? Schedule to respawn a new one!
|
||||||
if (container->GetAlive() || container->GetID()==Catapult) container->ScheduleCall(container, CustomAI.DoWeaponRespawn, 5, 1, GetID());
|
if (container->GetAlive() || container->GetID()==Catapult) container->ScheduleCall(container, CustomAI.DoWeaponRespawn, 5, 1, GetID());
|
||||||
this.Departure = nil;
|
this.Departure = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoWeaponRespawn(id_weapon)
|
func DoWeaponRespawn(id_weapon)
|
||||||
{
|
{
|
||||||
if (GetAlive() || GetID()==Catapult)
|
if (GetAlive() || GetID()==Catapult)
|
||||||
{
|
{
|
||||||
var re_weapon = CreateContents(id_weapon);
|
var re_weapon = CreateContents(id_weapon);
|
||||||
if (re_weapon) re_weapon.Departure = CustomAI.Departure_WeaponRespawn;
|
if (re_weapon) re_weapon.Departure = CustomAI.Departure_WeaponRespawn;
|
||||||
return re_weapon;
|
return re_weapon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Inventory_GetCarryTransform()
|
func Inventory_GetCarryTransform()
|
||||||
{
|
{
|
||||||
if (GetID().GetCarryTransform)
|
if (GetID().GetCarryTransform)
|
||||||
return Trans_Mul(Call(GetID().GetCarryTransform, ...), this.ExtraTransform);
|
return Trans_Mul(Call(GetID().GetCarryTransform, ...), this.ExtraTransform);
|
||||||
else
|
else
|
||||||
return this.ExtraTransform;
|
return this.ExtraTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
func LaunchEnemy(proplist enemy, int xmin, int xrange, int y)
|
func LaunchEnemy(proplist enemy, int xmin, int xrange, int y)
|
||||||
{
|
{
|
||||||
// Create enemy (usually a Clonk)
|
// Create enemy (usually a Clonk)
|
||||||
var x = xmin+Random(xrange);
|
var x = xmin+Random(xrange);
|
||||||
var obj = CreateObjectAbove(enemy.Type ?? Clonk, x,y, ENEMY), clonk;
|
var obj = CreateObjectAbove(enemy.Type ?? Clonk, x,y, ENEMY), clonk;
|
||||||
if (!obj) return nil;
|
if (!obj) return nil;
|
||||||
obj->SetController(ENEMY);
|
obj->SetController(ENEMY);
|
||||||
obj->MakeCrewMember(ENEMY);
|
obj->MakeCrewMember(ENEMY);
|
||||||
// Enemy visuals
|
// Enemy visuals
|
||||||
if (enemy.Skin)
|
if (enemy.Skin)
|
||||||
{
|
{
|
||||||
if (GetType(enemy.Skin) == C4V_Array)
|
if (GetType(enemy.Skin) == C4V_Array)
|
||||||
{
|
{
|
||||||
obj->SetSkin(enemy.Skin[0]);
|
obj->SetSkin(enemy.Skin[0]);
|
||||||
obj->SetMeshMaterial(enemy.Skin[1]);
|
obj->SetMeshMaterial(enemy.Skin[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
obj->SetSkin(enemy.Skin);
|
obj->SetSkin(enemy.Skin);
|
||||||
}
|
}
|
||||||
if (GetType(enemy.Backpack)) obj->~RemoveBackpack();
|
if (GetType(enemy.Backpack)) obj->~RemoveBackpack();
|
||||||
if (enemy.Scale) obj->SetMeshTransformation(Trans_Scale(enemy.Scale[0], enemy.Scale[1], enemy.Scale[2]), CLONK_MESH_TRANSFORM_SLOT_Scale);
|
if (enemy.Scale) obj->SetMeshTransformation(Trans_Scale(enemy.Scale[0], enemy.Scale[1], enemy.Scale[2]), CLONK_MESH_TRANSFORM_SLOT_Scale);
|
||||||
if (enemy.Name) obj->SetName(enemy.Name);
|
if (enemy.Name) obj->SetName(enemy.Name);
|
||||||
obj->SetColor(enemy.Color);
|
obj->SetColor(enemy.Color);
|
||||||
// Physical properties
|
// Physical properties
|
||||||
obj.MaxEnergy = (enemy.Energy ?? 50) * 1000;
|
obj.MaxEnergy = (enemy.Energy ?? 50) * 1000;
|
||||||
obj->DoEnergy(10000);
|
obj->DoEnergy(10000);
|
||||||
if (enemy.Speed)
|
if (enemy.Speed)
|
||||||
{
|
{
|
||||||
// Speed: Modify Speed in all ActMap entries
|
// Speed: Modify Speed in all ActMap entries
|
||||||
if (obj.ActMap == obj.Prototype.ActMap) obj.ActMap = new obj.ActMap {};
|
if (obj.ActMap == obj.Prototype.ActMap) obj.ActMap = new obj.ActMap {};
|
||||||
for (var action in /*obj.ActMap->GetProperties()*/ ["Walk", "Scale", "Dig", "Swim", "Hangle", "Jump", "WallJump", "Dive", "Push"]) // obj.ActMap->GetProperties() doesn't work :(
|
for (var action in /*obj.ActMap->GetProperties()*/ ["Walk", "Scale", "Dig", "Swim", "Hangle", "Jump", "WallJump", "Dive", "Push"]) // obj.ActMap->GetProperties() doesn't work :(
|
||||||
{
|
{
|
||||||
if (action == "Prototype") continue;
|
if (action == "Prototype") continue;
|
||||||
if (obj.ActMap[action] == obj.Prototype.ActMap[action]) obj.ActMap[action] = new obj.ActMap[action] {};
|
if (obj.ActMap[action] == obj.Prototype.ActMap[action]) obj.ActMap[action] = new obj.ActMap[action] {};
|
||||||
obj.ActMap[action].Speed = obj.ActMap[action].Speed * enemy.Speed / 100;
|
obj.ActMap[action].Speed = obj.ActMap[action].Speed * enemy.Speed / 100;
|
||||||
}
|
}
|
||||||
obj.JumpSpeed = obj.JumpSpeed * enemy.Speed / 100;
|
obj.JumpSpeed = obj.JumpSpeed * enemy.Speed / 100;
|
||||||
obj.FlySpeed = obj.FlySpeed * enemy.Speed / 100;
|
obj.FlySpeed = obj.FlySpeed * enemy.Speed / 100;
|
||||||
}
|
}
|
||||||
obj.MaxContentsCount = 1;
|
obj.MaxContentsCount = 1;
|
||||||
// Reward for killing enemy
|
// Reward for killing enemy
|
||||||
obj.Bounty = enemy.Bounty;
|
obj.Bounty = enemy.Bounty;
|
||||||
// Vehicles
|
// Vehicles
|
||||||
var vehicle;
|
var vehicle;
|
||||||
if (enemy.Vehicle)
|
if (enemy.Vehicle)
|
||||||
{
|
{
|
||||||
vehicle = CreateObjectAbove(enemy.Vehicle, x,y);
|
vehicle = CreateObjectAbove(enemy.Vehicle, x,y);
|
||||||
obj->SetAction("Push", vehicle);
|
obj->SetAction("Push", vehicle);
|
||||||
}
|
}
|
||||||
// Enemy inventory
|
// Enemy inventory
|
||||||
if (enemy.Inventory) for (var inv in ForceVal2Array(enemy.Inventory))
|
if (enemy.Inventory) for (var inv in ForceVal2Array(enemy.Inventory))
|
||||||
{
|
{
|
||||||
var inv_type = inv.InvType;
|
var inv_type = inv.InvType;
|
||||||
if (!inv_type) inv_type = inv;
|
if (!inv_type) inv_type = inv;
|
||||||
var inv_obj = obj->CreateContents(inv_type);
|
var inv_obj = obj->CreateContents(inv_type);
|
||||||
if (inv_obj)
|
if (inv_obj)
|
||||||
{
|
{
|
||||||
// Marker for custom weapon behaviour
|
// Marker for custom weapon behaviour
|
||||||
inv_obj.IsAIWeapon = true;
|
inv_obj.IsAIWeapon = true;
|
||||||
// Infinite ammo
|
// Infinite ammo
|
||||||
inv_obj->~SetInfiniteStackCount();
|
inv_obj->~SetInfiniteStackCount();
|
||||||
if (GetIndexOf(g_respawning_weapons, inv_type) >= 0) inv_obj.Departure = CustomAI.Departure_WeaponRespawn;
|
if (GetIndexOf(g_respawning_weapons, inv_type) >= 0) inv_obj.Departure = CustomAI.Departure_WeaponRespawn;
|
||||||
// Extra settings?
|
// Extra settings?
|
||||||
if (inv.InvType)
|
if (inv.InvType)
|
||||||
{
|
{
|
||||||
// Visuals
|
// Visuals
|
||||||
if (inv.Scale) { inv_obj.GetCarryTransform = CustomAI.Inventory_GetCarryTransform; inv_obj.ExtraTransform = Trans_Scale(inv.Scale, inv.Scale, inv.Scale); }
|
if (inv.Scale) { inv_obj.GetCarryTransform = CustomAI.Inventory_GetCarryTransform; inv_obj.ExtraTransform = Trans_Scale(inv.Scale, inv.Scale, inv.Scale); }
|
||||||
if (inv.Material) inv_obj->SetMeshMaterial(inv.Material);
|
if (inv.Material) inv_obj->SetMeshMaterial(inv.Material);
|
||||||
// Strength
|
// Strength
|
||||||
if (inv.Strength) inv_obj->SetStrength(inv.Strength);
|
if (inv.Strength) inv_obj->SetStrength(inv.Strength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Flying AI
|
// Flying AI
|
||||||
if (obj->~HasNoNeedForAI())
|
if (obj->~HasNoNeedForAI())
|
||||||
{
|
{
|
||||||
// Flying enemies all init themselves to fly at the statue at the moment
|
// Flying enemies all init themselves to fly at the statue at the moment
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Init AI: Run towards statue
|
// Init AI: Run towards statue
|
||||||
CustomAI->AddAI(obj);
|
CustomAI->AddAI(obj);
|
||||||
CustomAI->SetMaxAggroDistance(obj, LandscapeWidth());
|
CustomAI->SetMaxAggroDistance(obj, LandscapeWidth());
|
||||||
var fx = obj.ai;
|
var fx = obj.ai;
|
||||||
if (fx) fx.vehicle = vehicle;
|
if (fx) fx.vehicle = vehicle;
|
||||||
if (g_statue)
|
if (g_statue)
|
||||||
{
|
{
|
||||||
CustomAI->SetHome(obj, g_statue->GetX(), g_statue->GetY(), Random(2));
|
CustomAI->SetHome(obj, g_statue->GetX(), g_statue->GetY(), Random(2));
|
||||||
CustomAI->SetGuardRange(obj, 0,0,LandscapeWidth(),LandscapeHeight()); // nowhere to run!
|
CustomAI->SetGuardRange(obj, 0,0,LandscapeWidth(),LandscapeHeight()); // nowhere to run!
|
||||||
CustomAI->SetEnemyData(obj, enemy);
|
CustomAI->SetEnemyData(obj, enemy);
|
||||||
// CustomAI->SetGuardRange(obj, g_statue->GetX()-200, g_statue->GetY()-50, 400, 100);
|
// CustomAI->SetGuardRange(obj, g_statue->GetX()-200, g_statue->GetY()-50, 400, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remember this clonk to end wave when all enemies have been killed
|
// Remember this clonk to end wave when all enemies have been killed
|
||||||
g_spawned_enemies[GetLength(g_spawned_enemies)] = obj;
|
g_spawned_enemies[GetLength(g_spawned_enemies)] = obj;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper: put single elements into array
|
// helper: put single elements into array
|
||||||
//
|
//
|
||||||
global func ForceVal2Array(v) { if (GetType(v) != C4V_Array) return [v]; else return v; }
|
global func ForceVal2Array(v) { if (GetType(v) != C4V_Array) return [v]; else return v; }
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue