📄 monsterai.pas
字号:
unit MonsterAI;
interface
uses
Windows, StdCtrls, MMSystem, Classes, SysUtils, ScktComp, List32, Common, Path;
procedure CalcAI(tm:TMap; ts:TMob; Tick:Cardinal);
procedure MobSpawn(tm:TMap; ts:TMob; Tick:cardinal);
//procedure MobSkillCalc(tm:TMap;ts:TMob;Tick:cardinal);
//procedure MobSkillChance(tm:TMap; ts:TMob; tsAI:TMobAIDB; Tick:cardinal);
procedure MobSkills(tm:TMap; ts:TMob; Tick:cardinal);
procedure MobFieldSkills(tm:TMap; ts:TMob; Tick:cardinal);
procedure MobStatSkills(tm:TMap; ts:TMob; Tick:cardinal);
procedure MobSkillDamageCalc(tm:TMap; tc:TChara; ts:TMob; Tick:cardinal);
procedure SendMSkillAttack(tm:TMap; tc:TChara; ts:TMob; Tick:cardinal; k:integer);
//procedure MonsterCastTime(tm:Tmap; ts:TMob; Tick:cardinal);
procedure LoadMonsterAIData(tm:TMap; ts:TMob; Tick:cardinal);
procedure CalculateSkillIf(tm:TMap; ts:TMob; Tick:cardinal);
procedure CheckSkill(tm:TMap; ts:TMob; tsAI2:TMobAIDBFusion; Tick:Cardinal);
procedure NewMonsterCastTime(tm:TMap; ts:TMob; Tick:Cardinal);
procedure PetAttackSkill(tm:TMap; ts:TMob; tc:TChara);
procedure PetDamageProcess(tm:TMap; ts:TMob; tc:TChara; Dmg:integer; Tick:cardinal; isBreak:Boolean = True);
procedure SendPetSkillAttack(tm:TMap; tc:TChara; ts:TMob; Tick:cardinal; SkillID:integer);
function DamageProcess2(tm:TMap; tc:TChara; tc1:TChara; Dmg:integer; Tick:cardinal; isBreak:Boolean = True) : Boolean; {Player Attacking Player}
function DamageProcess3(tm:TMap; ts:TMob; tc1:TChara; Dmg:integer; Tick:cardinal; isBreak:Boolean = True) : Boolean; {Monster Attacking Player}
var
dmg :array[0..7] of integer;
implementation
(*-----------------------------------------------------------------------------*
Monster's AI
ChrstphR 2004/04/25 - cleaned up two potential memory leaks
- Exit; called without freeing the TStringList sl that is created in the code.
*-----------------------------------------------------------------------------*)
procedure CalcAI(tm:TMap; ts:TMob; Tick:Cardinal);
var
j : Integer;
i1 : Integer;
j1 : Integer;
k1 : Integer;
tc1 : TChara; //ref only
ts2 : TMob; //ref only
tn : TNPC; //ref only
sl : TStringList;
//ref list that is reused *shudder* to hold string indexes and object refs
//Early exits mean this must be free'd before Exit called.
begin
//if ts.Data.Loaded = false then TempNewAIProcedures(tm, ts, Tick);
with ts do begin
//MobSkillCalc(tm,ts,Tick);
if (ts.Stat1 <> 0) and (Data.Range1 > 0) then begin
pcnt := 0;
Exit;//ChrstphrR 2004/04/25 - safe
end;
if (isLeader) and ( (MonsterMob) or ((isSummon) and (SummonMonsterMob)) )then begin
if (SlaveCount = 0) and (Random(1000) <= 10) then begin
WFIFOW( 0, $011a);
WFIFOW( 2, 196);
WFIFOW( 4, 1);
WFIFOL( 6, ID);
WFIFOL(10, ID);
WFIFOB(14, 1);
SendBCmd(tm, ts.Point, 15);
MobSpawn(tm,ts,Tick);
end;
end;//if isLeader...
sl := TStringList.Create;//ChrstphrR - moved closer to first use..
if (ATarget = 0) then begin
if isActive then begin
//sl.Clear; //First use of SL, it's already empty :)
for j1 := Point.Y div 8 - 2 to Point.Y div 8 + 2 do begin
for i1 := Point.X div 8 - 2 to Point.X div 8 + 2 do begin
for k1 := 0 to tm.Block[i1][j1].CList.Count - 1 do begin
tc1 := tm.Block[i1][j1].CList.Objects[k1] as TChara;
if (tc1.HP > 0) and (tc1.Hidden = false) and (tc1.Paradise = false) and ((ts.isGuardian <> tc1.GUildID) or (ts.isGuardian = 0)) and (abs(ts.Point.X - tc1.Point.X) <= 10) and (abs(ts.Point.Y - tc1.Point.Y) <= 10) then begin //edited by The Harbinger -- darkWeiss Version
if (tc1.Sit <> 1) or (tc1.Option < 64) then begin
sl.AddObject(IntToStr(tc1.ID), tc1);
end;
end;//if
end;//for k1
end;//for i1
end;//for j1
if sl.Count > 0 then begin
j := Random(sl.Count);
ATarget := StrToInt(sl.Strings[j]);
ARangeFlag := false;
AData := sl.Objects[j];
ATick := Tick;
ARangeFlag := false;
sl.Free;// Must Free up open local objects before exiting routine
Exit;//ChrstphrR 2004/04/25 - safe
end;
end;
if (NOT isLooting) AND Data.isLoot then begin
sl.Clear;
for j1 := Point.Y div 8 - 2 to Point.Y div 8 + 2 do begin
for i1 := Point.X div 8 - 2 to Point.X div 8 + 2 do begin
for k1 := 0 to tm.Block[i1][j1].NPC.Count - 1 do begin
tn := tm.Block[i1][j1].NPC.Objects[k1] as TNPC;
if tn.CType <> 3 then Continue;
if (abs(tn.Point.X - Point.X) <= 10) and (abs(tn.Point.Y - Point.Y) <= 10) then begin
sl.AddObject(IntToStr(tn.ID), tn);
end;
end;
end;
end;
if sl.Count > 0 then begin
j := Random(sl.Count);
tn := sl.Objects[j] as TNPC;
j := SearchPath2(path, tm, Point.X, Point.Y, tn.Point.X, tn.Point.Y);
if (j <> 0) then begin
isLooting := True;
ATarget := tn.ID;
ATick := Tick;
pcnt := j;
ppos := 0;
MoveTick := Tick;
tgtPoint := tn.Point;
end;
sl.Free;// Must Free up open local objects before exiting routine
Exit;//ChrstphrR 2004/04/25 - safe
end;
end;
//if ATarget=0 ...
end else begin //ATarget > 0
if isLeader AND NOT isLooting then begin
for j1 := Point.Y div 8 - 2 to Point.Y div 8 + 2 do begin
for i1 := Point.X div 8 - 2 to Point.X div 8 + 2 do begin
for k1 := 0 to tm.Block[i1][j1].Mob.Count - 1 do begin
if (tm.Block[i1][j1].Mob.Objects[k1] is TMob) then begin
ts2 := tm.Block[i1][j1].Mob.Objects[k1] as TMob;
if (ts2 <> nil) or (ts2 <> ts) then begin
if ts2.LeaderID <> ts.ID then continue;
if (abs(ts.Point.X - ts2.Point.X) <= 10) and (abs(ts.Point.Y - ts2.Point.Y) <= 10) then begin
if ts2.ATarget = 0 then begin
ts2.ATarget := ts.ATarget;
ts2.ARangeFlag := false;
ts2.AData := ts.AData;
ts2.ATick := Tick;
ts2.ARangeFlag := false;
end;
end;
end;
end;
end;
end;
end;
end;
if Data.isLink AND NOT isLooting then begin
for j1 := Point.Y div 8 - 2 to Point.Y div 8 + 2 do begin
for i1 := Point.X div 8 - 2 to Point.X div 8 + 2 do begin
for k1 := 0 to tm.Block[i1][j1].Mob.Count - 1 do begin
ts2 := tm.Block[i1][j1].Mob.Objects[k1] AS TMob;
if (ts2 <> nil) or (ts2 <> ts) then begin
if ts2.JID <> ts.JID then Continue;
if (abs(ts.Point.X - ts2.Point.X) <= 10) and (abs(ts.Point.Y - ts2.Point.Y) <= 10) then begin
if ts2.ATarget = 0 then begin
ts2.ATarget := ts.ATarget;
ts2.ARangeFlag := false;
ts2.AData := ts.AData;
ts2.ATick := Tick;
ts2.ARangeFlag := false;
end;
end;
end;
end;//for k1
end;//for i1
end;//for j1
end;//if Data.isLink
end;//if-else ATarget=0/ATarget>0
//ChrstphrR - if the 2 early Exit's don't stop the flow, this existing
//call will free up the StringList before we leave.
sl.Free;
end;//with ts
end;(* proc CalcAI()
*-----------------------------------------------------------------------------*)
//------------------------------------------------------------------------------
{Spawn Monster}
procedure MobSpawn(tm:TMap; ts:TMob; Tick:cardinal);
var
i, j, k, h, m :integer;
tc :TChara;
ts1 :TMob;
tss :TSlaveDB;
begin
//if (MonsterMob = true) then begin
begin
k := SlaveDBName.IndexOf(ts.Data.Name);
if (k <> -1) then begin
ts.isLeader := true;
tss := SlaveDBName.Objects[k] as TSlaveDB;
if ts.Data.Name = tss.Name then begin
h := tss.TotalSlaves;
ts.SlaveCount := h;
repeat
for i := 0 to 4 do begin
if (tss.Slaves[i] <> -1) and (h <> 0) then begin
ts1 := TMob.Create;
ts1.Data := MobDBName.Objects[tss.Slaves[i]] as TMobDB;
ts1.ID := NowMobID;
Inc(NowMobID);
ts1.Name := ts1.Data.JName;
ts1.JID := ts1.Data.ID;
ts1.LeaderID := ts.ID;
ts1.Data.isLink := false;
ts1.Map := ts.Map;
ts1.Point.X := ts.Point.X + Random(10);
ts1.Point.Y := ts.Point.Y + Random(10);
ts1.Dir := ts.Dir;
ts1.HP := ts1.Data.HP;
if ts.Data.Speed < ts1.Data.Speed then begin
ts1.Speed := ts.Data.Speed;
end else begin
ts1.Speed := ts1.Data.Speed;
end;
ts1.SpawnDelay1 := $7FFFFFFF;
ts1.SpawnDelay2 := 0;
ts1.SpawnType := 0;
ts1.SpawnTick := 0;
if ts1.Data.isDontMove then
ts1.MoveWait := $FFFFFFFF
else
ts1.MoveWait := timeGetTime();
ts1.ATarget := 0;
ts1.ATKPer := 100;
ts1.DEFPer := 100;
ts1.DmgTick := 0;
ts1.Element := ts1.Data.Element;
ts1.isActive := false;
for j := 0 to 31 do begin
ts1.EXPDist[j].CData := nil;
ts1.EXPDist[j].Dmg := 0;
end;
if ts1.Data.MEXP <> 0 then begin
for j := 0 to 31 do begin
ts1.MVPDist[j].CData := nil;
ts1.MVPDist[j].Dmg := 0;
end;
ts1.MVPDist[0].Dmg := ts1.Data.HP * 30 div 100; //FA偵30%壛嶼
end;
ts1.isSummon := true;
ts1.isSlave := true;
tm.Mob.AddObject(ts1.ID, ts1);
tm.Block[ts1.Point.X div 8][ts1.Point.Y div 8].Mob.AddObject(ts1.ID, ts1);
for j := ts1.Point.Y div 8 - 2 to ts1.Point.Y div 8 + 2 do begin
for m := ts1.Point.X div 8 - 2 to ts1.Point.X div 8 + 2 do begin
for k := 0 to tm.Block[m][j].CList.Count - 1 do begin
tc := tm.Block[m][j].CList.Objects[k] as TChara;
if tc = nil then continue;
if (abs(ts1.Point.X - tc.Point.X) < 16) and (abs(ts1.Point.Y - tc.Point.Y) < 16) then begin
SendMData(tc.Socket, ts1);
SendBCmd(tm,ts1.Point,41,tc,False);
end;
end;
end;
end;
h := h - 1;
end;
end;
until (h <= 0);
end;
end;
end;
end;
//------------------------------------------------------------------------------
// Darkhelmet, Ah, my classic AI, i'll leave it here commented out just because
// of good times with it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -