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.