www.pudn.com > M2Server.rar > ObjectMonster.pas
////////////////////////////////////////////////////////////////////////////////
// //
// 工程: M2Server //
// 版本: 1.0 //
// 公司: 乐都在线 //
// 网址: http://www.hh8.net //
// 日期: 2005-05-28 //
// //
////////////////////////////////////////////////////////////////////////////////
unit ObjectMonster;
interface
uses
Classes, Windows, Math, SysUtils, ClassDeclaration, ObjectNPC, ObjectEngine,
Contnrs;
type
THolySeizeInfo = class
public
Event: array[0..7] of TObject;
SeizeList: TThreadList;
dwOpenTime: LongWord;
dwSeizeTime: LongWord;
end;
type
TMonsterObject = class(TNPCObject)
public
// Public Variable decalrations
m_nRace: Integer;
Feature: TOBJECTFEATURE_RCD;
m_dwNextWalkTime: LongWord;
m_dwHitTime: LongWord;
m_dwNextHitTime: LongWord;
m_dwThinkTime: LongWord;
m_dwSearchEnemyTime: LongWord;
m_nTargetX: Integer;
m_nTargetY: Integer;
m_btTargetDir: Byte;
m_dwRunAwayTime: LongWord;
m_dwRunAwayStart: LongWord;
m_dwExpHitTime: LongWord;
m_dwLastHitTime: LongWord;
m_nFindPathTime: LongWord;
m_fDupMode: Boolean;
m_fRunAwayMode: Boolean;
m_fNoAttackMode: Boolean;
m_fHasMission: Boolean;
m_nMissionX: Integer;
m_nMissionY: Integer;
m_nFightExp: Integer;
m_wEscape: Word;
m_btLifeAttrib: Byte;
m_fBoHolySeize: Boolean;
m_dwHolySeizeStart: LongWord;
m_dwHolySeizeTime: LongWord;
m_dwGold: LongWord;
m_xTGenItemRcd: TThreadList;
m_xTItemRcd: TThreadList;
// Public Method and Function decalrations
constructor Create;
function Think: Boolean;
function Attack: Boolean;
function IsFrontObject(pCharObject: TCharObject): Boolean;
procedure Struck(pHitter: TCharObject);
procedure SetLastHiter(pHitter: TCharObject);
procedure GotoTargetXY;
function TargetInAttackRange: Boolean;
function TargetInSpitRange(var nTargetDir: Integer): Boolean;
procedure Wondering;
procedure MonsterNormalAttack;
function MakeClone(nMonRace: Integer): TMonsterObject;
procedure MakeHolySeize(dwHTime: LongWord);
procedure BreakHolySeize;
procedure ComeOut;
procedure ComeDown;
function CheckComeOut(nValue: Integer): Boolean;
procedure Initialize;
procedure InheritedRun;
procedure KickException;
procedure Die;
procedure ScatterBagItems;
procedure MakeGenItem(lptGenItemRcd: PGENERALITEM_RCD);
procedure MonGetRandomItems;
function IsProperTarget(pTargetObject: TCharObject): Boolean; override;
procedure Operate; virtual;
function AttackTarget: Boolean; virtual;
function WalkTo(nDir: Integer): Boolean; override;
procedure SearchViewRange; override;
procedure Run; override;
function GetThisCharColor: Word; override;
procedure GetCharName(var pszCharName: string); override;
end;
// TGenneralMonObject 类的声明
TGenneralMonObject = class(TMonsterObject)
public
procedure Run; override;
end;
// TAnimalObject 类的声明对应 CMonsterObject
TAnimalObject = class(TMonsterObject)
public
m_fSkeleton: Boolean;
m_nMeatQuality: Integer;
m_nBodyLeathery: Integer;
end;
// TChickenObject 类的声明对应 CChickenObject
TChickenObject = class(TAnimalObject)
public
constructor Create;
procedure Run; override;
end;
// TScultureObject 类的声明对应 CScultureObject
TScultureObject = class(TMonsterObject)
public
constructor Create;
procedure MeltStone;
procedure MeltStoneAll;
procedure Run; override;
end;
// TScultureKingObject 类的声明对应于CScultureKingObject
TScultureKingObject = class(TMonsterObject)
protected
m_SlaveObjectList: TThreadList;
m_nDangerLevel: Integer;
public
constructor Create;
procedure MeltStone;
procedure CallSlave;
procedure Run; override;
end;
// TBeeQueen 类的声明对应类CBeeQueen
TBeeQueen = class(TMonsterObject)
protected
m_SlaveObjectList: TThreadList;
public
constructor Create;
// procedure CallSlave;
procedure MakeChildBee;
procedure Operate; override;
procedure Run; override;
end;
// TDualAxeObject 类的声明对应类 CDualAxeObject
TDualAxeObject = class(TMonsterObject)
protected
m_nChainShot: Integer;
m_nChainShotCount: Integer;
public
constructor Create; overload;
constructor Create(nChainShotCount: Integer); overload;
procedure FlyAxeAttack(pTargetObject: TCharObject);
function AttackTarget: Boolean; override;
procedure Run; override;
end;
// TLightingZombiObject 类的声明对应类 CLightingZombiObject
TLightingZombiObject = class(TMonsterObject)
public
constructor Create;
procedure LightingAttack(nDir: Integer);
procedure Run; override;
end;
// TRonObject 类的声明对应类 CRonObject
TRonObject = class(TGenneralMonObject)
public
procedure AroundAttack;
procedure Run; override;
end;
// TMinorNumaObject 类的声明对应 CMinorNumaObject
TMinorNumaObject = class(TMonsterObject)
public
procedure Run; override;
end;
// TOmaObject 类的声明对应 COmaObject
TOmaObject = class(TMonsterObject)
public
procedure Run; override;
end;
// TStickObject 类的声明对应 CStickObject
TStickObject = class(TMonsterObject)
public
constructor Create;
procedure Run; override;
end;
// TSandMobObject 类的声明对应 CSandMobObject
TSandMobObject = class(TMonsterObject)
public
m_dwAppearStart: LongWord;
constructor Create;
procedure Run; override;
end;
// TStickObject 类的声明对应 CStickObject
TRockManObject = class(TMonsterObject)
public
constructor Create;
procedure Run; override;
end;
// TWhiteSkeleton 类的声明对应 CWhiteSkeleton
TWhiteSkeleton = class(TGenneralMonObject)
protected
m_fIsFirst: Boolean;
public
constructor Create;
procedure ResetSkeleton;
procedure Run; override;
end;
// TSpitSpiderMonster 类的声明对应 CSpitSpiderMonster
TSpitSpiderMonster = class(TGenneralMonObject)
public
constructor Create;
procedure SpitAttack(nDir: Integer);
function AttackTarget: Boolean; override;
end;
// TElfMonster 类的声明对应 CElfMonster
TElfMonster = class(TMonsterObject)
protected
m_fIsFirst: Boolean;
public
constructor Create;
procedure AppearNow;
procedure ResetElfMon;
procedure Run; override;
end;
// TElfWarriorMonster 类的声明对应 CElfWarriorMonster
TElfWarriorMonster = class(TSpitSpiderMonster)
protected
m_fIsFirst: Boolean;
public
constructor Create;
procedure AppearNow;
procedure ResetElfMon;
procedure Run; override;
end;
implementation
uses PredefinedData, ObjectPlayer, GlobalDefinition, DataHandler;
constructor TMonsterObject.Create;
begin
m_dwRunNextTick := 250;
m_dwSearchTick := 3000 + Random(32767) mod 2000;
m_nDirection := 4;
m_pTargetObject := nil;
m_btTargetDir := 0;
m_pExpHitterObject := nil;
m_dwHitTime := 0;
m_fIsDead := False;
m_fHideMode := False;
m_btLight := 0;
m_fDupMode := False;
m_fRunAwayMode := False;
m_fNoAttackMode := False;
m_fHasMission := False;
m_fBoHolySeize := False;
m_dwSearchEnemyTime := GetTickCount;
m_dwThinkTime := GetTickCount;
m_wObjectType := _OBJECT_MONSTER;
m_btAntiMagic := 0;
m_dwGold := 0;
m_xVisibleEventList := TThreadList.Create;
m_xVisibleItemList := TThreadList.Create;
m_xVisibleEventList := TThreadList.Create;
m_xCacheObjectList := TThreadList.Create;
m_xVisibleObjectList := TThreadList.Create;
m_ProcessQ := TQueue.Create;
m_DelayProcessQ := TQueue.Create;
end;
procedure TMonsterObject.KickException;
begin
m_fIsDead := True;
m_dwDeathTime := GetTickCount;
MakeGhost;
end;
function TMonsterObject.MakeClone(nMonRace: Integer): TMonsterObject;
var
pMonRaceInfo: PMONRACEINFO_RCD;
pMonsterObject: TMonsterObject;
pPlayerObject: TPlayerObject;
begin
pMonRaceInfo := @g_pMonRaceInfo[nMonRace];
if pMonRaceInfo <> nil then
begin
pMonsterObject := TMonsterObject(AddCreatureSysop(m_nCurrX, m_nCurrY,
pMonRaceInfo, False));
if pMonsterObject <> nil then
begin
pMonsterObject.m_pMasterObject := m_pMasterObject;
if m_pMasterObject <> nil then
begin
pPlayerObject := TPlayerObject(pPlayerObject.m_pMasterObject);
if pPlayerObject <> nil then
pPlayerObject.m_xSlaveObjList.Add(pMonsterObject);
end;
pMonsterObject.m_WAbility := m_WAbility;
CopyMemory(@pMonsterObject.m_wStatusArr[0], @m_wStatusArr[0],
SizeOf(m_wStatusArr));
pMonsterObject.m_pTargetObject := m_pTargetObject;
pMonsterObject.m_dwTargetFocusTime := m_dwTargetFocusTime;
pMonsterObject.m_pLastHitterObject := m_pLastHitterObject;
pMonsterObject.m_dwLastHitTime := m_dwLastHitTime;
pMonsterObject.m_nDirection := m_nDirection;
Result := pMonsterObject;
end;
end;
Result := nil;
end;
function TMonsterObject.IsProperTarget(pTargetObject: TCharObject): Boolean;
var
fFlag: Boolean;
pPlayerObject: TPlayerObject;
begin
fFlag := False;
if (pTargetObject = self) or (pTargetObject = nil) then
begin
Result := fFlag;
Exit;
end;
if (pTargetObject.m_wObjectType and _OBJECT_HUMAN) > 0 then
begin
pPlayerObject := TPlayerObject(pTargetObject);
if pPlayerObject <> nil then
begin
if pPlayerObject.IsEmpty then
begin
Result := fFlag;
Exit;
end;
end;
end;
if m_pMasterObject <> nil then
begin
if m_pMasterObject.m_pTargetObject = pTargetObject then
begin
fFlag := True;
end;
if pTargetObject.m_pTargetObject <> nil then
begin
if (pTargetObject.m_pTargetObject = m_pMasterObject) or
(pTargetObject.m_pTargetObject.m_pMasterObject = m_pMasterObject) then
begin
fFlag := True;
end;
end;
if pTargetObject.m_pTargetObject = self then
begin
fFlag := True;
end;
end
else
begin
if (pTargetObject.m_wObjectType and _OBJECT_HUMAN) > 0 then
begin
fFlag := True;
end;
if pTargetObject.m_pMasterObject <> nil then
begin
fFlag := True;
end;
end;
Result := fFlag;
end;
procedure TMonsterObject.GetCharName(var pszCharName: string);
var
szMasterName: string;
begin
pszCharName := m_szName;
if m_pMasterObject <> nil then
begin
m_pMasterObject.GetCharName(szMasterName);
pszCharName := pszCharName + '(' + szMasterName + ')';
end;
end;
procedure TMonsterObject.MakeHolySeize(dwHTime: LongWord);
begin
m_fBoHolySeize := True;
m_dwHolySeizeStart := GetTickCount;
m_dwHolySeizeTime := dwHTime;
AddRefMsg(RM_CHANGENAMECOLOR, 0, 0, 0, 0, '');
end;
procedure TMonsterObject.BreakHolySeize;
begin
if m_fBoHolySeize then
begin
m_fBoHolySeize := False;
AddRefMsg(RM_CHANGENAMECOLOR, 0, 0, 0, 0, '');
end;
end;
{走}
function TMonsterObject.WalkTo(nDir: Integer): Boolean;
var
nX, nY: Integer;
begin
if m_fBoHolySeize then
begin
Result := False;
end;
WalkNextPos(nDir, nX, nY);
if m_wEscape > 0 then
begin
if not TMirMap(m_pMap).CanMove(nX, nY) then
begin
Result := False;
Exit;
end;
end;
Result := WalkXY(nX, nY, nDir);
end;
{死亡}
procedure TMonsterObject.Die;
var
nExp: Integer;
pPlayerObject: TPlayerObject;
pMonsterObject: TMonsterObject;
begin
if m_pExpHitterObject <> nil then
begin
pPlayerObject := TPlayerObject(m_pExpHitterObject);
if pPlayerObject <> nil then
begin
nExp := pPlayerObject.CalcGetExp(m_Ability.Level, m_nFightExp);
pPlayerObject.GainExp(nExp);
end
else
begin
pMonsterObject := TMonsterObject(m_pExpHitterObject);
if pMonsterObject <> nil then
begin
if pMonsterObject.m_pMasterObject <> nil then
begin
pPlayerObject := TPlayerObject(pMonsterObject.m_pMasterObject);
nExp := pPlayerObject.CalcGetExp(m_Ability.Level, m_nFightExp);
pPlayerObject.GainExp(nExp);
end;
end;
end;
end;
ScatterBagItems; //暴物品
if m_pMasterObject <> nil then
begin
FreeAndNil(m_pMasterObject);
end;
inherited Die;
end;
{解包}
procedure TMonsterObject.ScatterBagItems;
var
I: Integer;
lptUserItemRcd: PTCLIENTITEM;
begin
lptUserItemRcd := nil;
if m_xTItemRcd = nil then
Exit;
with m_xTItemRcd.LockList do
begin
for I := COunt - 1 downto 0 do // Iterate
begin
lptUserItemRcd := items[I];
if lptUserItemRcd <> nil then
begin
DropItemDown(lptUserItemRcd, 3, False);
end;
Delete(I);
end; // for
end; // with
m_xTItemRcd.UnlockList;
end;
{初始化怪物}
procedure TMonsterObject.Initialize;
begin
if m_nRace < 0 then
m_nRace := 0;
m_szName := g_pMonRaceInfo[m_nRace].szMonName;
TMirMap(m_pMap).AddNewObject(m_nCurrX, m_nCurrY, OS_MOVINGOBJECT, self);
m_tFeature.btHair := g_pMonRaceInfo[m_nRace].nAppear mod 255;
m_tFeature.btWear := g_pMonRaceInfo[m_nRace].nAppear div 255;
m_tFeature.btGender := g_pMonRaceInfo[m_nRace].nRaceImg;
AddRefMsg(RM_TURN, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
//MonGetRandomItems;
m_btLifeAttrib := g_pMonRaceInfo[m_nRace].btUndead;
m_Ability.Level := g_pMonRaceInfo[m_nRace].Level;
m_Ability.HP := g_pMonRaceInfo[m_nRace].HP;
m_Ability.MaxHP := g_pMonRaceInfo[m_nRace].HP;
m_Ability.MP := g_pMonRaceInfo[m_nRace].MP;
m_Ability.MaxMP := g_pMonRaceInfo[m_nRace].MP;
m_Ability.AC := g_pMonRaceInfo[m_nRace].AC;
m_Ability.MAC := g_pMonRaceInfo[m_nRace].MAC;
m_Ability.DC := g_pMonRaceInfo[m_nRace].DC;
m_Ability.MC := 0;
m_Ability.SC := 0;
m_nFightExp := g_pMonRaceInfo[m_nRace].Exp;
m_WAbility := m_Ability;
m_btSpeedPoint := Byte(g_pMonRaceInfo[m_nRace].Speed);
m_btHitPoint := Byte(g_pMonRaceInfo[m_nRace].Hit);
m_dwNextWalkTime := g_pMonRaceInfo[m_nRace].dwWalkSpeed;
m_dwNextHitTime := g_pMonRaceInfo[m_nRace].dwAttackSpeed;
m_wEscape := g_pMonRaceInfo[m_nRace].wEscape;
m_nViewRange := 5;
end;
procedure TMonsterObject.MakeGenItem(lptGenItemRcd: PGENERALITEM_RCD);
var
strValue: string;
begin
strValue := Format('G%03d%04d%04d', [lptGenItemRcd^.nStdIndex,
lptGenItemRcd^.nDura, lptGenItemRcd^.nDuraMax]);
CopyMemory(@lptGenItemRcd.szMakeIndex[1], @strValue[1], 12);
m_xTGenItemRcd.Add(lptGenItemRcd);
end;
procedure TMonsterObject.MonGetRandomItems;
var
I: Integer;
pMonItem: PMONITEM_RCD;
pMonRaceInfo: PMONRACEINFO_RCD;
lpTItemRcd: PUSERITEM_RCD;
lptGenItemRcd: PGENERALITEM_RCD;
begin
pMonRaceInfo := @g_pMonRaceInfo[m_nRace];
if pMonRaceInfo <> nil then
begin
with pMonRaceInfo^.m_xMonItemList.LockList do
begin
for I := 0 to COunt - 1 do // Iterate
begin
pMonItem := items[I];
if pMonItem <> nil then
begin
New(lpTItemRcd);
case pMonItem^.btItemType of //
_ITEM_GOLD:
begin
m_dwGold := pMonItem^.wCount div 2 + (Random(32767) mod
pMonItem^.wCount);
end;
_ITEM_WEAPON, _ITEM_ARMOR, _ITEM_ACCESSORY:
begin
ZeroMemory(@lpTItemRcd^.szPrefixName[1],
Length(lpTItemRcd^.szPrefixName));
ZeroMemory(@lpTItemRcd^.btValue[1],
Length(lpTItemRcd^.btValue));
lpTItemRcd^.nStdIndex := pMonItem^.wItemIndex;
case pMonItem^.btItemType of //
0: lpTItemRcd^.szMakeIndex := 'A00000000000';
1: lpTItemRcd^.szMakeIndex := 'B00000000000';
2: lpTItemRcd^.szMakeIndex := 'C00000000000';
end; // case
lpTItemRcd^.nDura :=
g_pStdItemSpecial[lpTItemRcd^.nStdIndex].wDuraMax;
lpTItemRcd^.nDuraMax :=
g_pStdItemSpecial[lpTItemRcd^.nStdIndex].wDuraMax;
if (Random(32767) mod 10) = 0 then
begin
g_pStdItemSpecial[pMonItem^.wItemIndex].UpgradeRandomItem(@lpTItemRcd^.btValue[0], lpTItemRcd^.nDura, lpTItemRcd^.nDuraMax);
end;
m_xTItemRcd.Add(lpTItemRcd);
end;
_ITEM_ETC:
begin
New(lptGenItemRcd);
if lptGenItemRcd <> nil then
begin
lptGenItemRcd^.nStdIndex := pMonItem^.wItemIndex;
lptGenItemRcd^.nDura :=
g_pStdItemEtc[pMonItem^.wItemIndex].wDuraMax;
lptGenItemRcd^.nDuraMax :=
g_pStdItemEtc[pMonItem^.wItemIndex].dwRSource;
MakeGenItem(lptGenItemRcd);
end;
end;
end; // case
end;
end; // for
end; // with
pMonRaceInfo^.m_xMonItemList.UnlockList;
end;
end;
{搜索可视范围}
procedure TMonsterObject.SearchViewRange;
var
I, N: Integer;
nX, nY: Integer;
pOSObject: POSOBJECT_RCD;
pMapCellInfo: PMAPCELLINFO_RCD;
pVisibleObject: TVisibleObject;
pCharObject: TCharObject;
X, Y: Integer;
nStartX, nEndX,
nStartY, nEndY: Integer;
begin
with m_xVisibleObjectList.LockList do
begin
for I := 0 to COunt - 1 do // Iterate
begin
pVisibleObject := items[I];
if pVisibleObject <> nil then
begin
pVisibleObject.nVisibleFlag := 0;
end;
end; // for
end; // with
m_xVisibleObjectList.UnlockList;
m_nViewRange := 15;
nStartX := m_nCurrX - m_nViewRange;
nEndX := m_nCurrX + m_nViewRange;
nStartY := m_nCurrY - m_nViewRange;
nEndY := m_nCurrY + m_nViewRange;
for X := nStartX to nEndX do // Iterate
begin
for Y := nStartY to nEndY do
begin
pMapCellInfo := TMirMap(m_pMap).GetMapCellInfo(X, Y);
if pMapCellInfo <> nil then
begin
if pMapCellInfo^.m_xpObjectList = nil then
Continue;
with pMapCellInfo^.m_xpObjectList.LockList do
begin
for N := 0 to COunt - 1 do // Iterate
begin
pOSObject := items[N];
if pOSObject <> nil then
begin
if pOSObject^.btType = OS_MOVINGOBJECT then
begin
pCharObject := TCharObject(pOSObject^.pObject);
if pCharObject.m_wObjectType = _OBJECT_HUMAN then
begin
m_pTargetObject := pCharObject;
m_dwTargetFocusTime := GetTickCount;
end;
UpdateVisibleObject(pCharObject);
end;
end;
end; // for
end;
pMapCellInfo^.m_xpObjectList.UnlockList;
end; // with
end;
end; // for
with m_xVisibleObjectList.LockList do
begin
for I := COunt - 1 downto 0 do // Iterate
begin
pVisibleObject := items[I];
if pVisibleObject.nVisibleFlag = 0 then
begin
FreeAndNil(pVisibleObject);
Delete(I);
end;
end; // for
end; // with
m_xVisibleObjectList.UnlockList;
end;
{目标是不是在前面}
function TMonsterObject.IsFrontObject(pCharObject: TCharObject): Boolean;
var
I: Integer;
begin
for I := 0 to 7 do
begin
if (pCharObject.m_nCurrX = m_nCurrX + Integer(g_SearchTable[I].X)) and
(pCharObject.m_nCurrY = m_nCurrY + Integer(g_SearchTable[I].Y)) then
begin
Result := True;
Exit;
end;
end;
Result := False;
end;
{设置最后攻击人物}
procedure TMonsterObject.SetLastHiter(pHitter: TCharObject);
var
dwHitTick: LongWord;
begin
dwHitTick := GetTickCount;
m_pLastHitterObject := pHitter;
m_dwLastHitTime := dwHitTick;
if m_pExpHitterObject = nil then
begin
m_pExpHitterObject := pHitter;
m_dwExpHitTime := dwHitTick;
end
else
begin
if m_pExpHitterObject = pHitter then
begin
m_dwExpHitTime := dwHitTick;
end;
end;
end;
{显示}
procedure TMonsterObject.Wondering;
var
dir: Integer;
begin
Randomize;
if (Random(20)) < 4 then
begin
Randomize;
if (Random(4)) = 1 then
begin
Randomize;
dir := Random(8);
if dir <> m_nDirection then
TurnTo(dir);
end
else
begin
WalkTo(m_nDirection);
end;
end;
end;
{到指定的坐标}
procedure TMonsterObject.GotoTargetXY;
var
I: Integer;
nX, nY, nDir: Integer;
nOldX, nOldY: Integer;
pVisibleObject: TVisibleObject;
begin
if (m_nCurrX <> m_nTargetX) or (m_nCurrY <> m_nTargetY) then
begin
with m_xVisibleObjectList.LockList do
begin
pVisibleObject := items[0];
if pVisibleObject <> nil then
begin
if (pVisibleObject.pCharObject.m_szName <> m_pTargetObject.m_szName) and
(pVisibleObject.pCharObject.m_wObjectType = _OBJECT_HUMAN) and (not
pVisibleObject.pCharObject.m_fIsDead) and
IsProperTarget(pVisibleObject.pCharObject) and (not
pVisibleObject.pCharObject.m_fInspector) then
begin
if (abs(m_nCurrX - pVisibleObject.pCharObject.m_nCurrX) + abs(m_nCurrY
- pVisibleObject.pCharObject.m_nCurrY)) <
(abs(m_nCurrY - m_nTargetX) + abs(m_nCurrY - m_nTargetY)) then
begin
SelectTarget(pVisibleObject.pCharObject);
m_nTargetX := pVisibleObject.pCharObject.m_nCurrX;
m_nTargetY := pVisibleObject.pCharObject.m_nCurrY;
Exit;
end;
end;
end;
end; // with
m_xVisibleObjectList.UnlockList;
nX := m_nTargetX;
nY := m_nTargetY;
m_nFindPathTime := GetTickCount;
if nX > m_nCurrX then
begin
nDir := DR_RIGHT;
if nY > m_nCurrY then
begin
nDir := DR_DOWNRIGHT;
end
else if nY < m_nCurrY then
begin
nDir := DR_UPRIGHT;
end;
end;
if nX < m_nCurrX then
begin
nDir := DR_LEFT;
if nY > m_nCurrY then
begin
nDir := DR_DOWNLEFT;
end
else if nY < m_nCurrY then
begin
nDir := DR_UPLEFT;
end;
end;
if nY > m_nCurrY then
begin
nDir := DR_DOWN;
end;
if nY < m_nCurrY then
begin
nDir := DR_UP;
end;
nOldX := m_nCurrX;
nOldY := m_nCurrY;
WalkTo(nDir);
for I := 0 to 6 do
begin
if (nOldX = m_nCurrX) and (nOldY = m_nCurrY) then
begin
if (Random(32767) mod 3) > 0 then
Inc(nDir)
else if nDir > 0 then
Dec(nDir)
else
nDir := 7;
if nDir > 7 then
nDir := 0;
WalkTo(nDir);
end
else
Break;
end; // for
end;
end;
{攻击}
procedure TMonsterObject.Struck(pHitter: TCharObject);
begin
if pHitter <> nil then
begin
if IsProperTarget(pHitter) then
begin
SelectTarget(pHitter);
end;
end;
if m_Ability.Level < 50 then
begin
m_dwHitTime := m_dwHitTime + (150 - Min(130, m_Ability.Level * 4));
end;
end;
{}
function TMonsterObject.GetThisCharColor: Word;
begin
if m_fBoHolySeize then
begin
Result := _CHAT_COLOR4;
Exit;
end;
Result := _CHAT_COLOR3;
end;
procedure TMonsterObject.Operate;
var
I, nCount: Integer;
nVal: Integer;
lpProcessMsg: PPROCESSMSG_RCD;
begin
Run;
nCount := m_ProcessQ.COunt;
for I := 0 to nCount - 1 do
begin
lpProcessMsg := PPROCESSMSG_RCD(m_ProcessQ.Pop);
case lpProcessMsg^.wIdent of //
RM_STRUCK:
begin
if (lpProcessMsg^.pCharObject = self) and (lpProcessMsg^.lParam3 > 0)
then
begin
SetLastHiter(TCharObject(lpProcessMsg^.lParam3));
Struck(TCharObject(lpProcessMsg^.lParam3));
//Die();
m_dwHealthTick := 0;
m_dwSpellTick := 0;
Dec(m_btPerHealth);
Dec(m_btPerSpell);
// BreakHolySeize;
end;
end;
RM_MAGSTRUCK, RM_MAGSTRUCK_MINE:
begin
if lpProcessMsg^.wIdent = RM_MAGSTRUCK then
begin
if m_Ability.Level < 50 then
begin
m_dwWalkTime := m_dwWalkTime + 800 + (Random(32767) mod 1000);
end;
end;
nVal := GetMagStruckDamage(lpProcessMsg^.lParam1);
if nVal > 0 then
begin
StruckDamage(nVal);
HealthSpellChanged;
AddRefMsg(RM_STRUCK_MAG, nVal, m_WAbility.HP, m_WAbility.MP,
Integer(lpProcessMsg^.pCharObject), '');
SetLastHiter(lpProcessMsg^.pCharObject);
m_dwHealthTick := 0;
m_dwSpellTick := 0;
BreakHolySeize;
end;
end;
RM_DEATH:
begin
end;
end; // case
FreeMem(lpProcessMsg);
lpProcessMsg := nil;
end;
nCount := m_DelayProcessQ.COunt - 1;
for I := 0 to nCount do // Iterate
begin
lpProcessMsg := PPROCESSMSG_RCD(m_DelayProcessQ.Pop);
if lpProcessMsg <> nil then
begin
if GetTickCount < lpProcessMsg^.dwDeliveryTime then
begin
m_DelayProcessQ.Push(lpProcessMsg);
Continue;
end;
case lpProcessMsg^.wIdent of //
RM_DOOPENHEALTH: MakeOpenHealth;
RM_STRUCK:
begin
if (lpProcessMsg^.pCharObject.m_wObjectType = _OBJECT_HUMAN) then
begin
lpProcessMsg^.pCharObject.AddRefMsg(RM_STRUCK,
lpProcessMsg^.wParam, lpProcessMsg^.lParam1,
lpProcessMsg^.lParam2, lpProcessMsg^.lParam3, '');
end;
end;
RM_MAGSTRUCK:
begin
AddProcess(lpProcessMsg^.pCharObject, lpProcessMsg^.wIdent,
lpProcessMsg^.wParam, lpProcessMsg^.lParam1,
lpProcessMsg^.lParam2, lpProcessMsg^.lParam3, '');
end;
end; // case
FreeMem(lpProcessMsg);
lpProcessMsg := nil;
end;
end; // for
end;
{普通攻击}
procedure TMonsterObject.MonsterNormalAttack;
var
I: Integer;
pVisibleObject: TVisibleObject;
begin
with m_xVisibleObjectList.LockList do
begin
for I := 0 to COunt - 1 do // Iterate
begin
pVisibleObject := items[I];
if pVisibleObject <> nil then
begin
if (not pVisibleObject.pCharObject.m_fIsDead) and
IsProperTarget(pVisibleObject.pCharObject) and
(not pVisibleObject.pCharObject.m_fInspector) and (not
pVisibleObject.pCharObject.m_fHumHideMode) then
begin
if (abs(m_nCurrX - pVisibleObject.pCharObject.m_nCurrX) + abs(m_nCurrY
- pVisibleObject.pCharObject.m_nCurrY)) < 999 then
begin
SelectTarget(pVisibleObject.pCharObject);
Exit;
end;
end;
end;
end; // for
end; // with
m_xVisibleObjectList.UnlockList;
end;
{判断目标在不在攻击范围}
function TMonsterObject.TargetInAttackRange: Boolean;
begin
if m_pTargetObject <> nil then
begin
if (m_pTargetObject.m_nCurrX >= m_nCurrX - 1) and (m_pTargetObject.m_nCurrX
<= m_nCurrX + 1) and
(m_pTargetObject.m_nCurrY >= m_nCurrY - 1) and (m_pTargetObject.m_nCurrY
<= m_nCurrY + 1) and
not ((m_pTargetObject.m_nCurrX = m_nCurrX) and (m_pTargetObject.m_nCurrY =
m_nCurrY)) then
begin
if (m_pTargetObject.m_nCurrX = m_nCurrX - 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY) then
begin
m_btTargetDir := DR_LEFT;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX + 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY) then
begin
m_btTargetDir := DR_RIGHT;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX) and (m_pTargetObject.m_nCurrY =
m_nCurrY - 1) then
begin
m_btTargetDir := DR_UP;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX) and (m_pTargetObject.m_nCurrY =
m_nCurrY + 1) then
begin
m_btTargetDir := DR_DOWN;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX - 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY - 1) then
begin
m_btTargetDir := DR_UPLEFT;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX + 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY - 1) then
begin
m_btTargetDir := DR_UPRIGHT;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX - 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY + 1) then
begin
m_btTargetDir := DR_DOWNLEFT;
Result := True;
Exit;
end;
if (m_pTargetObject.m_nCurrX = m_nCurrX + 1) and (m_pTargetObject.m_nCurrY
= m_nCurrY + 1) then
begin
m_btTargetDir := DR_DOWNRIGHT;
Result := True;
Exit;
end;
end;
end;
Result := False;
end;
{攻击范围}
function TMonsterObject.TargetInSpitRange(var nTargetDir: Integer): Boolean;
var
nX, nY: Integer;
begin
nX := 0;
nY := 0;
if (abs(m_pTargetObject.m_nCurrX - m_nCurrX) <= 2) and
(abs(m_pTargetObject.m_nCurrY - m_nCurrY) <= 2) then
begin
nX := m_pTargetObject.m_nCurrX - m_nCurrX;
nY := m_pTargetObject.m_nCurrY - m_nCurrY;
if (abs(nX) <= 1) and (abs(nY) <= 1) then
begin
Result := TargetInAttackRange;
Exit;
end
else
begin
nX := nX + 2;
nY := nY + 2;
if ((nX >= 0) and (nX <= 4)) and ((nY >= 0) and (nY <= 4)) then
begin
nTargetDir := GetNextDirection(m_pTargetObject.m_nCurrX,
m_pTargetObject.m_nCurrY);
if g_SpitMap[nTargetDir][nX][nY] = 1 then
begin
Result := True;
Exit;
end;
end;
end;
end;
Result := False;
end;
{是不是攻击}
function TMonsterObject.Attack: Boolean;
begin
m_nDirection := Integer(m_btTargetDir);
if TargetInSpitRange(m_nDirection) then
begin
// AddRefMsg(RM_HIT, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
_Attack(CM_HIT, m_pTargetObject);
end;
Result := True;
end;
{是不是攻击的目标}
function TMonsterObject.AttackTarget: Boolean;
var
isok: Integer;
begin
if m_pTargetObject <> nil then
begin
if TargetInAttackRange then
begin
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
m_dwTargetFocusTime := GetTickCount;
if not m_pTargetObject.m_fIsDead then
Attack;
BreakHolySeize;
end;
Result := True;
Exit;
end
else
begin
if m_pTargetObject.m_pMap = m_pMap then
begin
m_nTargetX := m_pTargetObject.m_nCurrX;
m_nTargetY := m_pTargetObject.m_nCurrY;
GotoTargetXY;
end
else
begin
m_pTargetObject := nil;
m_nTargetX := -1;
m_nTargetY := -1;
end;
end;
end;
Result := False;
end;
function TMonsterObject.Think: Boolean;
var
nOldX, nOldY: Integer;
begin
if (GetTickCount - m_dwThinkTime) > 3000 then
begin
m_dwThinkTime := GetTickCount;
if TMirMap(m_pMap).GetDupCount(m_nCurrX, m_nCurrY) >= 2 then
begin
m_fDupMode := True;
end;
if m_pTargetObject <> nil then
begin
if not IsProperTarget(m_pTargetObject) then
begin
m_pTargetObject := nil;
end;
end;
end;
if m_fDupMode then
begin
nOldX := m_nCurrX;
nOldY := m_nCurrY;
WalkTo(Random(32767) mod 8);
if (nOldX <> m_nCurrX) or (nOldX <> m_nCurrX) then
begin
m_fDupMode := False;
Result := True;
Exit;
end;
end;
Result := False;
end;
procedure TMonsterObject.InheritedRun;
begin
if RestoreHealSpell then
begin
Die;
end;
inherited Run;
end;
procedure TMonsterObject.Run;
var
nX, nY: Integer;
begin
InheritedRun;
if (not m_fIsDead) and (not m_fHideMode) and (not m_fIsGhost) and (not
m_fStoneMode) and (m_wStatusArr[POISON_STONE] = 0) then
begin
if m_pTargetObject <> nil then
begin
if ((GetTickCount - m_dwTargetFocusTime) > 30000) or
m_pTargetObject.m_fIsDead or
m_pTargetObject.m_fIsGhost or (abs(m_pTargetObject.m_nCurrX - m_nCurrX)
> 15) or
(abs(m_pTargetObject.m_nCurrY - m_nCurrY) > 15) then
begin
m_pTargetObject := nil;
end;
end;
if m_fBoHolySeize then
begin
if (GetTickCount - m_dwHolySeizeStart) > m_dwHolySeizeTime then
begin
BreakHolySeize;
end;
end;
if Think then
begin
//InheritedRun;
Exit;
end;
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
m_dwWalkTime := GetTickCount;
if not m_fRunAwayMode then
begin
if not m_fNoAttackMode then
begin
if m_pTargetObject <> nil then
begin
if AttackTarget then
begin
// InheritedRun;
Exit;
end;
end
else
begin
m_nTargetX := -1;
if m_fHasMission then
begin
m_nTargetX := m_nMissionX;
m_nTargetY := m_nMissionY;
end;
end;
end;
if m_pMasterObject <> nil then
begin
if m_pTargetObject = nil then
begin
m_pMasterObject.GetBackPosition(nX, nY);
if (abs(m_nTargetX - nX) > 1) or (abs(m_nTargetY - nY) > 1) then
begin
m_nTargetX := nX;
m_nTargetY := nY;
if (abs(m_nCurrX - nX) <= 2) or (abs(m_nCurrY - nY) <= 2) then
begin
if TCharObject(TMirMap(m_pMap).GetObject(nX, nY)) <> nil then
begin
m_nTargetX := m_nCurrX;
m_nTargetY := m_nCurrY;
end;
end;
end;
end;
if (abs(m_nCurrX - m_pMasterObject.m_nCurrX) > 20) or (abs(m_nCurrY -
m_pMasterObject.m_nCurrY) > 20) then
begin
SpaceMove(m_nTargetX, m_nTargetY, m_pMasterObject.m_pMap);
end;
end;
end
else
begin
if m_dwRunAwayTime > 0 then
begin
if (GetTickCount - m_dwRunAwayStart) > m_dwRunAwayTime then
begin
m_fRunAwayMode := False;
m_dwRunAwayTime := 0;
end;
end;
end;
if m_nTargetX <> -1 then
begin
GotoTargetXY;
end
else
begin
if m_pTargetObject = nil then
begin
Wondering;
end;
end;
end;
end;
//InheritedRun;
end;
procedure TMonsterObject.ComeOut;
begin
m_fHideMode := False;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
end;
procedure TMonsterObject.ComeDown;
begin
AddRefMsg(RM_DIGDOWN, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
m_xVisibleObjectList.Clear;
m_fHideMode := True;
end;
function TMonsterObject.CheckComeOut(nValue: Integer): Boolean;
var
I: Integer;
pVisibleObject: TVisibleObject;
begin
with m_xVisibleObjectList.LockList do
begin
for I := 0 to COunt - 1 do // Iterate
begin
pVisibleObject := items[I];
if pVisibleObject <> nil then
begin
if (not pVisibleObject.pCharObject.m_fIsDead) and
IsProperTarget(pVisibleObject.pCharObject) and
(not pVisibleObject.pCharObject.m_fInspector) then
begin
if (abs(m_nCurrX - pVisibleObject.pCharObject.m_nCurrX) <= nValue) and
(abs(m_nCurrY - pVisibleObject.pCharObject.m_nCurrY) <= nValue) then
begin
Result := True;
m_xVisibleObjectList.UnlockList;
Exit;
end;
end;
end;
end; // for
end; // with
m_xVisibleObjectList.UnlockList;
Result := False;
end;
procedure TGenneralMonObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if (GetTickCount - m_dwSearchEnemyTime > 8000) or ((GetTickCount -
m_dwSearchEnemyTime > 1000) and (m_pTargetObject = nil)) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
end;
inherited Run;
end;
constructor TChickenObject.Create;
begin
m_nMeatQuality := 3000 + Random(32767) mod 2000;
m_nBodyLeathery := 50;
inherited Create;
end;
procedure TChickenObject.Run;
begin
end;
constructor TScultureObject.Create;
begin
m_dwSearchTick := 1500 + Random(32767) mod 1500;
m_fStoneMode := True;
m_nCharStatusEx := STATE_STONE_MODE;
m_nCharStatus := GetCharStatus;
inherited Create;
end;
procedure TScultureObject.MeltStone;
begin
m_nCharStatusEx := 0;
m_nCharStatus := GetCharStatus;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
m_fStoneMode := False;
end;
procedure TScultureObject.MeltStoneAll;
var
I: Integer;
ObjectList: TThreadList;
pTargetObject: TMonsterObject;
begin
MeltStone;
ObjectList := TThreadList.Create;
TMirMap(m_pMap).GetMapObject(m_nCurrX, m_nCurrY, 7, ObjectList);
with ObjectList.LockList do
begin
for I := COunt - 1 downto 0 do // Iterate
begin
pTargetObject := TMonsterObject(items[I]);
if pTargetObject <> nil then
begin
if pTargetObject.m_fStoneMode then
begin
if (pTargetObject.m_wObjectType and _OBJECT_MONSTER) > 0 then
begin
case pTargetObject.m_nRace of //
145, 148:
begin
TScultureObject(pTargetObject).MeltStone;
end;
end; // case
end;
end;
end;
Delete(I);
end; // for
end; // with
ObjectList.UnlockList;
end;
procedure TScultureObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) and (m_wStatusArr[POISON_STONE] = 0)
then
begin
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
if m_fStoneMode then
begin
if CheckComeOut(2) then
begin
MeltStoneAll;
m_dwWalkTime := GetTickCount + 2000;
end;
end
else
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
end;
end;
end;
inherited Run;
end;
constructor TScultureKingObject.Create;
begin
m_dwSearchTick := 1500 + Random(32767) mod 1500;
m_nDangerLevel := 5;
m_fStoneMode := True;
m_nCharStatusEx := STATE_STONE_MODE;
m_nCharStatus := GetCharStatus;
m_nDirection := 5;
inherited Create;
end;
procedure TScultureKingObject.CallSlave;
const
MaxSlaveList = 4;
SlaveList: array[0..3] of Integer = (143, 145, 148, 126);
var
nCount, nMonRace,
nX, nY, I: Integer;
pMonsterObject: TMonsterObject;
begin
nCount := 6 + (Random(32767) mod 6);
for I := 0 to nCount - 1 do
begin
if m_SlaveObjectList.LockList.COunt < 30 then
begin
nMonRace := SlaveList[Random(32767) mod MaxSlaveList];
GetFrontPosition(nX, nY);
pMonsterObject := TMonsterObject(AddCreatureSysop(nX, nY,
@g_pMonRaceInfo[nMonRace], False));
if pMonsterObject <> nil then
begin
m_SlaveObjectList.Add(pMonsterObject);
end;
end;
m_SlaveObjectList.UnlockList;
end;
end;
procedure TScultureKingObject.MeltStone;
begin
m_nCharStatusEx := 0;
m_nCharStatus := GetCharStatus;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
m_fStoneMode := False;
end;
procedure TScultureKingObject.Run;
var
I: Integer;
pMonsterObject: TMonsterObject;
begin
if (not m_fIsDead) and (not m_fIsGhost) and (m_wStatusArr[POISON_STONE] = 0)
then
begin
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
if m_fStoneMode then
begin
if CheckComeOut(2) then
begin
MeltStone;
m_dwWalkTime := GetTickCount + 2000;
end;
end
else
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
if ((m_WAbility.HP / m_WAbility.MaxHP * 5) < m_nDangerLevel) and
(m_nDangerLevel > 0) then
begin
Dec(m_nDangerLevel);
CallSlave;
end;
if m_WAbility.HP = m_WAbility.MaxHP then
begin
m_nDangerLevel := 5;
end;
end;
end;
with m_SlaveObjectList.LockList do
begin
for I := COunt - 1 downto 0 do
begin
pMonsterObject := items[I];
if pMonsterObject.m_fIsDead or pMonsterObject.m_fIsGhost then
begin
Delete(I);
end;
end; // for
end; // with
m_SlaveObjectList.UnlockList;
end;
inherited Run;
end;
constructor TBeeQueen.Create;
begin
m_dwSearchTick := 2500 + Random(32767) mod 1500;
m_fStickMode := True;
inherited Create;
end;
procedure TBeeQueen.MakeChildBee;
begin
if m_SlaveObjectList.LockList.COunt < 15 then
begin
AddRefMsg(RM_HIT, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
AddDelayProcess(self, RM_ZEN_BEE, 0, 0, 0, 0, '', 500);
end;
end;
procedure TBeeQueen.Operate;
var
I: Integer;
lpProcessMsg: PPROCESSMSG_RCD;
pMonsterObject: TMonsterObject;
begin
for I := 0 to m_DelayProcessQ.COunt - 1 do
begin
lpProcessMsg := PPROCESSMSG_RCD(m_DelayProcessQ.Pop);
if lpProcessMsg <> nil then
begin
if GetTickCount < lpProcessMsg^.dwDeliveryTime then
begin
m_DelayProcessQ.Push(lpProcessMsg);
Continue;
end;
case lpProcessMsg^.wIdent of //
RM_ZEN_BEE:
begin
pMonsterObject := TMonsterObject(AddCreatureSysop(m_nCurrX,
m_nCurrY, @g_pMonRaceInfo[_MONSTER_BEE], False));
if pMonsterObject <> nil then
begin
m_SlaveObjectList.Add(pMonsterObject);
pMonsterObject.SelectTarget(m_pTargetObject);
end;
end;
end; // case
FreeMem(lpProcessMsg);
lpProcessMsg := nil;
end;
end;
inherited Operate;
end;
procedure TBeeQueen.Run;
var
I: Integer;
pMonsterObject: TMonsterObject;
begin
if (not m_fIsDead) and (not m_fIsGhost) and (m_wStatusArr[POISON_STONE] = 0)
then
begin
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
m_dwWalkTime := GetTickCount;
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
MonsterNormalAttack;
if m_pTargetObject <> nil then
begin
MakeChildBee;
end;
end;
end;
with m_SlaveObjectList.LockList do
begin
for I := COunt - 1 downto 0 do
begin
pMonsterObject := items[I];
if pMonsterObject.m_fIsDead or pMonsterObject.m_fIsGhost then
begin
Delete(I);
end;
end;
end; // with
m_SlaveObjectList.UnlockList;
end;
inherited Run;
end;
constructor TDualAxeObject.Create;
begin
m_nChainShot := 0;
m_nChainShotCount := 2;
inherited Create;
end;
constructor TDualAxeObject.Create(nChainShotCount: Integer);
begin
m_nChainShot := 0;
m_nChainShotCount := nChainShotCount;
end;
procedure TDualAxeObject.FlyAxeAttack(pTargetObject: TCharObject);
var
nDamage, nDir: Integer;
begin
nDir := GetNextDirection(pTargetObject.m_nCurrX, pTargetObject.m_nCurrY);
if (HIBYTE(m_WAbility.DC) - LOBYTE(m_WAbility.DC) + 1) > 0 then
begin
nDamage := LOBYTE(m_WAbility.DC) + Random(32767) mod (HIBYTE(m_WAbility.DC)
- LOBYTE(m_WAbility.DC) + 1);
end
else
begin
nDamage := LOBYTE(m_WAbility.DC);
end;
if nDamage > 0 then
begin
nDamage := pTargetObject.GetHitStruckDamage(nDamage);
end;
if nDamage > 0 then
begin
pTargetObject.StruckDamage(nDamage);
pTargetObject.AddDelayProcess(pTargetObject, RM_STRUCK, nDamage,
pTargetObject.m_WAbility.HP, pTargetObject.m_WAbility.MaxHP,
Integer(self), '', 600 + max(abs(m_nCurrX - pTargetObject.m_nCurrX),
abs(m_nCurrY - pTargetObject.m_nCurrY) * 50));
end;
AddRefMsg(RM_FLYAXE, nDir, m_nCurrX, m_nCurrY, Integer(pTargetObject), '');
end;
function TDualAxeObject.AttackTarget: Boolean;
begin
if m_pTargetObject <> nil then
begin
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) < 7) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) < 7) then
begin
if m_nChainShot < (m_nChainShotCount - 1) then
begin
Inc(m_nChainShot);
m_dwTargetFocusTime := GetTickCount;
FlyAxeAttack(m_pTargetObject);
end
else
begin
if (Random(32767) mod 5) = 0 then
begin
m_nChainShot := 0;
end;
end;
Result := True;
Exit;
end
else
begin
if m_pTargetObject.m_pMap = m_pMap then
begin
m_nTargetX := m_pTargetObject.m_nCurrX;
m_nTargetY := m_pTargetObject.m_nCurrY;
end
else
begin
m_pTargetObject := nil;
m_nTargetX := -1;
m_nTargetY := -1;
end;
end;
end;
end;
Result := False;
end;
procedure TDualAxeObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if (GetTickCount - m_dwSearchEnemyTime) > 5000 then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
end;
end;
inherited Run;
end;
constructor TLightingZombiObject.Create;
begin
m_dwSearchTick := 1500 + Random(32767) mod 1500;
inherited Create;
end;
procedure TLightingZombiObject.LightingAttack(nDir: Integer);
var
nPwr,
nSX, nSY, nTX, nTY: Integer;
begin
m_nDirection := nDir;
AddRefMsg(RM_LIGHTING, 1, m_nCurrX, m_nCurrY, Integer(m_pTargetObject), '');
if GetNextPosition(nDir, 1, nSX, nSY) then
begin
GetNextPosition(nDir, 1, nTX, nTY);
nPwr := LOBYTE(m_WAbility.DC) + Random(32767) mod HIBYTE(m_WAbility.DC) -
LOBYTE(m_WAbility.DC) + 1;
MagPassThroughMagic(nSX, nSY, nTX, nTY, nDir, nPwr, True);
BreakHolySeize;
end;
end;
procedure TLightingZombiObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) and (m_wStatusArr[POISON_STONE] = 0)
then
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
if m_pTargetObject <> nil then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) < 4) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) < 4) then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) < 2) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) < 2) then
begin
if (Random(32767) mod 3) <> 0 then
begin
inherited Run;
Exit;
end;
end;
GetBackPosition(m_nTargetX, m_nTargetY);
end;
end;
end;
if m_pTargetObject <> nil then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) < 6) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) < 6) then
begin
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
LightingAttack(GetNextDirection(m_pTargetObject.m_nCurrX,
m_pTargetObject.m_nCurrY));
end;
end;
end;
end;
inherited Run;
end;
procedure TRonObject.AroundAttack;
var
I: Integer;
xTargetList: TThreadList;
pTargetObject: TCharObject;
begin
m_nDirection := Integer(m_btTargetDir);
xTargetList := TThreadList.Create;
TMirMap(m_pMap).GetMapObject(m_nCurrX, m_nCurrY, 1, xTargetList);
with xTargetList.LockList do
begin
for I := COunt - 1 downto 0 do
begin
pTargetObject := items[I];
if pTargetObject <> nil then
begin
_Attack(CM_HIT, pTargetObject);
end;
Delete(I);
end;
end; // with
xTargetList.UnlockList;
AddRefMsg(RM_HIT, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
end;
procedure TRonObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) and (m_wStatusArr[POISON_STONE] = 0)
then
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
if m_pTargetObject <> nil then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) < 6) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) < 6) then
begin
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
AroundAttack;
end;
end;
end;
end;
inherited Run;
end;
procedure TMinorNumaObject.Run;
begin
if not m_fIsDead then
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
end;
inherited Run;
end;
procedure TOmaObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
end;
end;
inherited Run;
end;
constructor TRockManObject.Create;
begin
m_fHideMode := True;
inherited Create;
end;
procedure TRockManObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if m_fHideMode then
begin
if CheckComeOut(8) then
begin
ComeOut;
end;
m_dwWalkTime := GetTickCount + 1000;
end
else
begin
if ((GetTickCount - m_dwSearchEnemyTime) > 8000) or ((GetTickCount -
m_dwSearchEnemyTime) > 1000) and (m_pTargetObject = nil) then
begin
m_dwSearchEnemyTime := GetTickCount;
MonsterNormalAttack;
if (m_pTargetObject = nil) then
begin
ComeDown;
end;
end;
end;
end;
inherited Run;
end;
constructor TStickObject.Create;
begin
m_dwSearchTick := 2500 + (Random(32767) mod 1500);
m_fHideMode := True;
inherited Create;
end;
procedure TStickObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
m_dwWalkTime := GetTickCount;
if m_fHideMode then
begin
if CheckComeOut(4) then
begin
ComeOut;
end;
end
else
begin
if m_pTargetObject <> nil then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) > 4) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) > 4) then
begin
ComeDown;
Exit;
end;
end;
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
MonsterNormalAttack;
end;
if not m_fHideMode then
begin
if AttackTarget then
begin
inherited Run;
end;
end;
end;
end;
end;
inherited Run;
end;
constructor TSandMobObject.Create;
begin
m_fHideMode := True;
inherited Create;
end;
procedure TSandMobObject.Run;
begin
if (not m_fIsDead) and (not m_fIsGhost) then
begin
if (GetTickCount - m_dwWalkTime) > m_dwNextWalkTime then
begin
m_dwWalkTime := GetTickCount;
if m_fHideMode then
begin
if (m_WAbility.HP > (m_WAbility.MaxHP div 20)) and CheckComeOut(8) then
begin
m_dwAppearStart := GetTickCount;
end;
end
else
begin
if (m_WAbility.HP > 0) and (m_WAbility.HP < (m_WAbility.MaxHP div 20))
and ((GetTickCount - m_dwAppearStart) > 3000) then
begin
ComeDown;
end
else if m_pTargetObject <> nil then
begin
if (abs(m_nCurrX - m_pTargetObject.m_nCurrX) > 15) and (abs(m_nCurrY -
m_pTargetObject.m_nCurrY) > 15) then
begin
ComeDown;
Exit;
end;
end;
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
MonsterNormalAttack;
end;
if not m_fHideMode then
begin
if AttackTarget then
begin
inherited Run;
end;
end;
end;
end;
end;
inherited Run;
end;
constructor TWhiteSkeleton.Create;
begin
m_fIsFirst := True;
m_fHideMode := True;
inherited Create;
end;
procedure TWhiteSkeleton.ResetSkeleton;
begin
m_dwWalkTime := GetTickCount + 2000;
end;
procedure TWhiteSkeleton.Run;
begin
if m_fIsFirst then
begin
m_fIsFirst := False;
m_nDirection := 5;
m_fHideMode := False;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
ResetSkeleton;
end;
inherited Run;
end;
constructor TElfMonster.Create;
begin
m_fNoAttackMode := True;
m_fIsFirst := True;
m_fHideMode := True;
inherited Create;
end;
procedure TElfMonster.ResetElfMon;
begin
m_dwWalkTime := GetTickCount + 2000;
end;
procedure TElfMonster.AppearNow;
begin
m_fIsFirst := False;
m_fHideMode := False;
m_dwWalkTime := GetTickCount + 800;
end;
procedure TElfMonster.Run;
var
fChangeFace: Boolean;
pElfWarriorMon: TElfWarriorMonster;
begin
if m_fIsFirst then
begin
m_fIsFirst := False;
m_fHideMode := False;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
ResetElfMon;
end;
if m_fIsDead then
begin
if (GetTickCount - m_dwDeathTime) > (2 * 1000) then
begin
MakeGhost;
end;
end
else
begin
fChangeFace := False;
if m_pTargetObject <> nil then
begin
fChangeFace := True;
end;
if m_pMasterObject <> nil then
begin
if m_pMasterObject.m_pTargetObject <> nil then
begin
fChangeFace := True;
end;
end;
if fChangeFace then
begin
pElfWarriorMon := TElfWarriorMonster(MakeClone(_MONSTER_ELFWARRIOR));
if pElfWarriorMon <> nil then
begin
pElfWarriorMon.AppearNow;
end;
m_pMasterObject := nil;
KickException;
Exit;
end;
end;
inherited Run;
end;
constructor TElfWarriorMonster.Create;
begin
m_fIsFirst := True;
inherited Create;
end;
procedure TElfWarriorMonster.ResetElfMon;
begin
m_dwWalkTime := GetTickCount + 2000;
end;
procedure TElfWarriorMonster.AppearNow;
begin
m_fIsFirst := False;
m_fHideMode := False;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
m_dwWalkTime := GetTickCount + 800;
end;
procedure TElfWarriorMonster.Run;
var
fChangeFace: Boolean;
pElfMonster: TElfMonster;
begin
if m_fIsFirst then
begin
m_fIsFirst := False;
m_fHideMode := False;
AddRefMsg(RM_DIGUP, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
ResetElfMon;
end;
if m_fIsDead then
begin
if (GetTickCount - m_dwDeathTime) > (2 * 1000) then
begin
MakeGhost;
end;
end
else
begin
fChangeFace := True;
if m_pTargetObject <> nil then
begin
fChangeFace := False;
end;
if m_pMasterObject <> nil then
begin
if m_pMasterObject.m_pTargetObject <> nil then
begin
fChangeFace := False;
end;
end;
if fChangeFace then
begin
pElfMonster := TElfMonster(MakeClone(_MONSTER_ELFMONSTER));
if pElfMonster <> nil then
begin
AddRefMsg(RM_DIGDOWN, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
AddRefMsg(RM_CHANGEFACE, 0, Integer(self), Integer(pElfMonster), 0, '');
pElfMonster.AppearNow;
end;
m_pMasterObject := nil;
KickException;
end;
end;
inherited Run;
end;
constructor TSpitSpiderMonster.Create;
begin
inherited Create; // Do nothing now
end;
procedure TSpitSpiderMonster.SpitAttack(nDir: Integer);
var
I, K: Integer;
nDamage, nX, nY: Integer;
pCharObject: TCharObject;
begin
m_nDirection := nDir;
if (HIBYTE(m_WAbility.DC) - LOBYTE(m_WAbility.DC) + 1) > 0 then
begin
nDamage := LOBYTE(m_WAbility.DC) + (Random(32767) mod (HIBYTE(m_WAbility.DC)
- LOBYTE(m_WAbility.DC) + 1));
end
else
nDamage := LOBYTE(m_WAbility.DC);
if nDamage < 0 then
Exit;
AddRefMsg(RM_HIT, m_nDirection, m_nCurrX, m_nCurrY, 0, '');
for I := 0 to 3 do // Iterate
begin
for K := 0 to 3 do
begin
if g_SpitMap[nDir][I][K] = 1 then
begin
nX := m_nCurrX - 2 + K;
nY := m_nCurrY - 2 + I;
pCharObject := TCharObject(TMirMap(m_pMap).GetObject(nX, nY));
if (pCharObject <> nil) and (pCharObject <> self) then
begin
if IsProperTarget(pCharObject) then
begin
if pCharObject.m_btSpeedPoint > 0 then
begin
if (Random(32767) mod pCharObject.m_btSpeedPoint) < m_btHitPoint
then
begin
nDamage := GetMagStruckDamage(nDamage);
if nDamage > 0 then
begin
pCharObject.StruckDamage(nDamage);
pCharObject.AddDelayProcess(pCharObject, RM_STRUCK, nDamage,
pCharObject.m_WAbility.HP,
pCharObject.m_WAbility.MaxHP, Integer(self), '', 300);
end;
end;
end;
end;
end;
end;
end; // for K
end; // for I
end;
function TSpitSpiderMonster.AttackTarget: Boolean;
var
nTargetDir: Integer;
begin
if m_pTargetObject <> nil then
begin
if TargetInSpitRange(nTargetDir) then
begin
if (GetTickCount - m_dwHitTime) > m_dwNextHitTime then
begin
m_dwHitTime := GetTickCount;
m_dwTargetFocusTime := GetTickCount;
SpitAttack(nTargetDir);
BreakHolySeize;
end;
Result := True;
Exit;
end
else
begin
if m_pTargetObject.m_pMap <> m_pMap then
begin
m_nTargetX := m_pTargetObject.m_nCurrX;
m_nTargetY := m_pTargetObject.m_nCurrY;
end
else
begin
m_pTargetObject := nil;
m_nTargetX := -1;
m_nTargetY := -1;
end;
end;
end;
Result := False;
end;
end.