forked from Mirrors/openclonk
FightForGidl: No friendly fire and some AI fixes.
parent
680505c078
commit
1dca9cf1b5
|
@ -9,6 +9,7 @@ func AddAI(object clonk)
|
|||
{
|
||||
clonk.ExecuteAI = CustomAI.Execute;
|
||||
fx.ai = CustomAI;
|
||||
fx.ignore_allies = true;
|
||||
}
|
||||
return fx;
|
||||
}
|
||||
|
@ -24,13 +25,12 @@ func SetEnemyData(object clonk, proplist data)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
func FindTarget(fx)
|
||||
{
|
||||
// Attack doors and statue unless an enemy clonk is closer than these objectives
|
||||
var objective;
|
||||
if (g_doorleft && GetX()<=g_doorleft ->GetX()+5) objective = g_doorleft;
|
||||
else if (g_doorright && GetX()>=g_doorright->GetX()-5) objective = g_doorright;
|
||||
if (g_doorleft && GetX()<=g_doorleft ->GetX()+5) objective = g_doorleft.dummy_target;
|
||||
else if (g_doorright && GetX()>=g_doorright->GetX()-5) objective = g_doorright.dummy_target;
|
||||
else objective = g_statue;
|
||||
var target = inherited(fx, ...);
|
||||
if (objective)
|
||||
|
@ -113,14 +113,6 @@ private func CheckVehicleAmmo(fx, object catapult)
|
|||
return true;
|
||||
}
|
||||
|
||||
func PathFree()
|
||||
{
|
||||
// ignore path checks to doors because of solidmask)
|
||||
var fx = GetEffect("AI", this);
|
||||
if (fx && fx.target && fx.target->GetID()==StoneDoor) return true;
|
||||
return inherited(...);
|
||||
}
|
||||
|
||||
func Execute(proplist fx, int time)
|
||||
{
|
||||
// Execution: No defensive AI. All enemies move towards target
|
||||
|
@ -207,6 +199,7 @@ func LaunchEnemy(proplist enemy, int x, int y)
|
|||
obj.JumpSpeed = obj.JumpSpeed * enemy.Speed / 100;
|
||||
}
|
||||
obj.MaxContentsCount = CustomAI.Clonk_MaxContentsCount;
|
||||
obj->MakeInvincibleToFriendlyFire();
|
||||
obj.MaxContentsCountVal = 1;
|
||||
// Reward for killing enemy
|
||||
obj.Bounty = enemy.Bounty;
|
||||
|
@ -229,7 +222,7 @@ func LaunchEnemy(proplist enemy, int x, int y)
|
|||
inv_obj.IsAIWeapon = true;
|
||||
// Infinite ammo
|
||||
inv_obj->~SetInfiniteStackCount();
|
||||
if (GetIndexOf(g_respawning_weapons, inv_type)) inv_obj.Departure = CustomAI.Departure_WeaponRespawn;
|
||||
if (GetIndexOf(g_respawning_weapons, inv_type) >= 0) inv_obj.Departure = CustomAI.Departure_WeaponRespawn;
|
||||
// Extra settings?
|
||||
if (inv.InvType)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[DefCore]
|
||||
id=DoorDummy
|
||||
Version=7,0
|
||||
Category=C4D_StaticBack | C4D_MouseIgnore
|
||||
Width=8
|
||||
Height=20
|
||||
Offset=-4,-10
|
||||
Vertices=1
|
||||
VertexY=10
|
|
@ -0,0 +1,3 @@
|
|||
/* Dummy object in place of doors, so AI doesn't try to hit doors that have moved up */
|
||||
|
||||
public func GetAlive() { return true; }
|
|
@ -21,6 +21,9 @@ static const MAX_RELAUNCH = 10;
|
|||
|
||||
func Initialize()
|
||||
{
|
||||
// Init door dummies
|
||||
g_doorleft.dummy_target = g_doorleft->CreateObject(DoorDummy, -6, 6);
|
||||
g_doorright.dummy_target = g_doorright->CreateObject(DoorDummy, +6, 6);
|
||||
// Wealth shown at all time
|
||||
GUI_Controller->ShowWealth();
|
||||
// Player homebase preparation
|
||||
|
@ -92,6 +95,7 @@ func JoinPlayer(plr, prev_clonk)
|
|||
}
|
||||
SetCursor(plr, clonk);
|
||||
clonk->DoEnergy(1000);
|
||||
clonk->MakeInvincibleToFriendlyFire();
|
||||
// contents
|
||||
clonk.MaxContentsCount = CustomAI.Clonk_MaxContentsCount;
|
||||
clonk.MaxContentsCountVal = 1;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/* When door goes down, remove its dummy */
|
||||
// (Doors have immovable dummies for the AI to punch on)
|
||||
|
||||
#appendto StoneDoor
|
||||
|
||||
func Destruction(...)
|
||||
{
|
||||
if (this.dummy_target) this.dummy_target->RemoveObject();
|
||||
return _inherited(...);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* Disable friendly fire */
|
||||
// This could also be a general rule
|
||||
|
||||
global func NOFF_QueryCatchBlow(object projectile, ...)
|
||||
{
|
||||
// 100% shield if allied
|
||||
var w_controller = projectile->GetController();
|
||||
var t_controller = GetController();
|
||||
if (w_controller >= 0) // NO_OWNER is probably lost controller management (e.g. chain reactions). Always hit.
|
||||
if ((t_controller == ENEMY) == (w_controller == ENEMY)) // ENEMY can't hit ENEMY and others can't hit others.
|
||||
return true; // reject
|
||||
if (this.NOFF_backup_qcb) return this->NOFF_backup_qcb(projectile, ...);
|
||||
return false;
|
||||
}
|
||||
|
||||
global func NOFF_BlastObject(int level, int caused_by, ...)
|
||||
{
|
||||
var w_controller = caused_by;
|
||||
var t_controller = GetController();
|
||||
if (w_controller >= 0) // NO_OWNER is probably lost controller management (e.g. chain reactions). Always hit.
|
||||
if ((t_controller == ENEMY) == (w_controller == ENEMY)) // ENEMY can't hit ENEMY and others can't hit others.
|
||||
return true; // reject
|
||||
return this->NOFF_backup_bo(level, caused_by, ...);
|
||||
}
|
||||
|
||||
global func NOFF_DoShockwaveCheck(int x, int y, int caused_by, ...)
|
||||
{
|
||||
var w_controller = caused_by;
|
||||
var t_controller = GetController();
|
||||
if (w_controller >= 0) // NO_OWNER is probably lost controller management (e.g. chain reactions). Always hit.
|
||||
if ((t_controller == ENEMY) == (w_controller == ENEMY)) // ENEMY can't hit ENEMY and others can't hit others.
|
||||
return false; // reject
|
||||
return this->NOFF_backup_sw(x, y, caused_by, ...);
|
||||
}
|
||||
|
||||
global func MakeInvincibleToFriendlyFire()
|
||||
{
|
||||
// Overload QueryCatchBlow
|
||||
if (this.QueryCatchBlow != Global.NOFF_QueryCatchBlow)
|
||||
{
|
||||
this.NOFF_backup_qcb = this.QueryCatchBlow;
|
||||
this.QueryCatchBlow = Global.NOFF_QueryCatchBlow;
|
||||
this.NOFF_backup_sw = this.DoShockwaveCheck ?? Global.DoShockwaveCheck;
|
||||
this.DoShockwaveCheck = Global.NOFF_DoShockwaveCheck;
|
||||
this.NOFF_backup_bo = this.BlastObject ?? Global.BlastObject;
|
||||
this.BlastObject = Global.NOFF_BlastObject;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* Disable friendly fire */
|
||||
// This could also be a general rule
|
||||
|
||||
#appendto Library_MeleeWeapon
|
||||
|
||||
public func ApplyShieldFactor(from, target, ...)
|
||||
{
|
||||
// 100% shield if allied
|
||||
var w_controller = from->GetController();
|
||||
var t_controller = target->GetController();
|
||||
if (w_controller >= 0) // NO_OWNER is probably lost controller management (e.g. chain reactions). Always hit.
|
||||
if ((t_controller == ENEMY) == (w_controller == ENEMY)) // ENEMY can't hit ENEMY and others can't hit others.
|
||||
return 100;
|
||||
// Otherwise regular check
|
||||
return inherited(from, target, ...);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/* Disable friendly fire */
|
||||
// This could also be a general rule
|
||||
|
||||
#appendto Arrow
|
||||
#appendto Javelin
|
||||
#appendto LeadShot
|
||||
#appendto Boompack
|
||||
#appendto Shrapnel
|
||||
|
||||
public func HitObject(object target, ...)
|
||||
{
|
||||
// Go by controller
|
||||
var w_controller = GetController();
|
||||
var t_controller = target->GetController();
|
||||
if (w_controller >= 0) // NO_OWNER is probably lost controller management (e.g. chain reactions). Always hit.
|
||||
if ((t_controller == ENEMY) == (w_controller == ENEMY)) // ENEMY can't hit ENEMY and others can't hit others.
|
||||
return false;
|
||||
// OK, hit it
|
||||
return inherited(target, ...);
|
||||
}
|
|
@ -14,7 +14,6 @@ static const AI_DefMaxAggroDistance = 200, // lose sight to target if it is this
|
|||
AI_DefGuardRangeX = 300, // search targets this far away in either direction (searching in rectangle)
|
||||
AI_DefGuardRangeY = 150, // search targets this far away in either direction (searching in rectangle)
|
||||
AI_AlertTime = 800; // number of frames after alert after which AI no longer checks for projectiles
|
||||
|
||||
/* Public interface */
|
||||
|
||||
// Add AI execution timer to target Clonk
|
||||
|
@ -76,6 +75,7 @@ func SetHome(object clonk, int x, int y, int dir)
|
|||
// Put into clonk proplist
|
||||
func AI_BindInventory() { return this.ai.ai->BindInventory(this); }
|
||||
func AI_SetHome() { return this.ai.ai->SetHome(this); }
|
||||
func AI_SetIgnoreAllies() { return (this.ai.ignore_allies = true); }
|
||||
|
||||
// Set the guard range to the provided rectangle
|
||||
func SetGuardRange(object clonk, int x, int y, int wdt, int hgt)
|
||||
|
@ -362,7 +362,9 @@ private func ExecuteRanged(fx)
|
|||
// Finish shooting process
|
||||
if (fx.post_aim_weapon)
|
||||
{
|
||||
if (IsAimingOrLoading()) return true;
|
||||
// wait max one second after shot (otherwise may be locked in wait animation forever if something goes wrong during shot)
|
||||
if (FrameCounter() - fx.post_aim_weapon_time < 36)
|
||||
if (IsAimingOrLoading()) return true;
|
||||
fx.post_aim_weapon = nil;
|
||||
}
|
||||
// Target still in guard range?
|
||||
|
@ -378,6 +380,7 @@ private func ExecuteRanged(fx)
|
|||
if (!fx.weapon->ControlUseStart(this, fx.target->GetX()-GetX(), fx.target->GetY()-GetY())) return false; // something's broken :(
|
||||
fx.aim_weapon = fx.weapon;
|
||||
fx.aim_time = fx.time;
|
||||
fx.post_aim_weapon = nil;
|
||||
// Enough for now
|
||||
return;
|
||||
}
|
||||
|
@ -391,7 +394,7 @@ private func ExecuteRanged(fx)
|
|||
var dt = d * 10 / fx.projectile_speed; // projected travel time of the arrow
|
||||
tx += GetTargetXDir(fx.target, dt);
|
||||
ty += GetTargetYDir(fx.target, dt);
|
||||
if (!fx.target->GetContact(-1)) ty += GetGravity()*dt*dt/200;
|
||||
if (!fx.target->GetContact(-1)) if (!fx.target->GetCategory() & C4D_StaticBack) ty += GetGravity()*dt*dt/200;
|
||||
// Path to target free?
|
||||
if (PathFree(x,y,tx,ty))
|
||||
{
|
||||
|
@ -405,7 +408,8 @@ private func ExecuteRanged(fx)
|
|||
if (GetType(shooting_angle) != C4V_Nil)
|
||||
{
|
||||
// No ally on path? Also search for allied animals, just in case.
|
||||
var ally = FindObject(Find_OnLine(0,0,tx-x,ty-y), Find_Exclude(this), Find_OCF(OCF_Alive), Find_Owner(GetOwner()));
|
||||
var ally;
|
||||
if (!fx.ignore_allies) ally = FindObject(Find_OnLine(0,0,tx-x,ty-y), Find_Exclude(this), Find_OCF(OCF_Alive), Find_Owner(GetOwner()));
|
||||
if (ally)
|
||||
{
|
||||
if (ExecuteJump()) return true;
|
||||
|
@ -423,6 +427,7 @@ private func ExecuteRanged(fx)
|
|||
//Log("Throw angle %v speed %v to reach %d %d", shooting_angle, fx.projectile_speed, tx-GetX(), ty-GetY());
|
||||
fx.aim_weapon->ControlUseStop(this, x,y);
|
||||
fx.post_aim_weapon = fx.aim_weapon; // assign post-aim status to allow slower shoot animations to pass
|
||||
fx.post_aim_weapon_time = FrameCounter();
|
||||
fx.aim_weapon = nil;
|
||||
}
|
||||
return true;
|
||||
|
@ -499,10 +504,23 @@ private func ExecuteStand(fx)
|
|||
SetCommand("None");
|
||||
if (GetProcedure() == "SCALE")
|
||||
{
|
||||
var tx;
|
||||
if (fx.target) tx = fx.target->GetX() - GetX();
|
||||
// Scale: Either scale up if target is beyond this obstacle or let go if it's not
|
||||
if (GetDir()==DIR_Left)
|
||||
ObjectControlMovement(GetOwner(), CON_Right, 100);
|
||||
{
|
||||
if (tx < -20)
|
||||
SetComDir(COMD_Left);//ObjectControlMovement(GetOwner(), CON_Up, 100); // scale up
|
||||
else
|
||||
ObjectControlMovement(GetOwner(), CON_Right, 100); // let go
|
||||
}
|
||||
else
|
||||
ObjectControlMovement(GetOwner(), CON_Left, 100);
|
||||
{
|
||||
if (tx > -20)
|
||||
SetComDir(COMD_Right);//ObjectControlMovement(GetOwner(), CON_Up, 100); // scale up
|
||||
else
|
||||
ObjectControlMovement(GetOwner(), CON_Left, 100); // let go
|
||||
}
|
||||
}
|
||||
else if (GetProcedure() == "HANGLE")
|
||||
{
|
||||
|
@ -566,6 +584,7 @@ private func ExecuteEvade(fx,int threat_dx,int threat_dy)
|
|||
|
||||
private func ExecuteJump(fx)
|
||||
{
|
||||
//LogCallStack("Jump");
|
||||
// Jump if standing on floor
|
||||
if (GetProcedure() == "WALK") // if (GetContact(-1, CNAT_Bottom)) - implied by walk
|
||||
{
|
||||
|
|
|
@ -277,7 +277,7 @@ global func DoShockwave(int x, int y, int level, int cause_plr, object layer)
|
|||
|
||||
// Hurl objects in explosion radius.
|
||||
var shockwave_objs = FindObjects(Find_Distance(level, l_x, l_y), Find_NoContainer(), Find_Layer(layer),
|
||||
Find_Or(Find_Category(C4D_Object|C4D_Living|C4D_Vehicle), Find_Func("CanBeHitByShockwaves")), Find_Func("DoShockwaveCheck", x, y));
|
||||
Find_Or(Find_Category(C4D_Object|C4D_Living|C4D_Vehicle), Find_Func("CanBeHitByShockwaves", cause_plr)), Find_Func("DoShockwaveCheck", x, y, cause_plr));
|
||||
var cnt = GetLength(shockwave_objs);
|
||||
if (cnt)
|
||||
{
|
||||
|
@ -323,7 +323,7 @@ global func DoShockwave(int x, int y, int level, int cause_plr, object layer)
|
|||
}
|
||||
}
|
||||
|
||||
global func DoShockwaveCheck(int x, int y)
|
||||
global func DoShockwaveCheck(int x, int y, int cause_plr)
|
||||
{
|
||||
var def = GetID();
|
||||
// Some special cases, which won't go into FindObjects.
|
||||
|
|
Loading…
Reference in New Issue