FightForGidl: No friendly fire and some AI fixes.

shapetextures
Sven Eberhardt 2015-12-11 23:29:27 -05:00
parent 680505c078
commit 1dca9cf1b5
10 changed files with 143 additions and 20 deletions

View File

@ -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)
{

View File

@ -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

View File

@ -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; }

View File

@ -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;

View File

@ -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(...);
}

View File

@ -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;
}

View File

@ -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, ...);
}

View File

@ -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, ...);
}

View File

@ -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
{

View File

@ -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.