www.pudn.com > M2Server.rar > ObjectEngine.pas


//////////////////////////////////////////////////////////////////////////////// 
//                                                                            // 
//                       工程:  M2Server                                     // 
//                       版本:   1.0                                          // 
//                       公司:  乐都在线                                     // 
//                       网址:  http://www.hh8.net                           // 
//                       日期:  2005-05-28                                   // 
//                                                                            // 
//////////////////////////////////////////////////////////////////////////////// 
 
unit ObjectEngine; 
 
interface 
 
uses 
  Classes, Math, Windows, SysUtils, ClassDeclaration, Contnrs, PredefinedData; 
 
type 
  TCharObject = class 
 
  public 
    m_pUserInfo: TObject; 
 
    m_ProcessQ: TQueue; 
    m_DelayProcessQ: TQueue; 
 
    m_nCurrX: Integer; 
    m_nCurrY: Integer; 
    m_nDirection: Integer; 
 
    m_nEvent: Integer; 
 
    m_btLight: Byte; 
 
    m_tFeature: TOBJECTFEATURE_RCD; 
    m_tFeatureEx: TOBJECTFEATUREEX_RCD; 
 
    m_pMap: TObject; 
 
    m_wObjectType: Word; 
 
    m_xVisibleObjectList: TThreadList; 
    m_xVisibleItemList: TThreadList; 
    m_xVisibleEventList: TThreadList; 
    m_xCacheObjectList: TThreadList; 
    m_dwCacheTick: LongWord; 
 
    m_nViewRange: Integer; 
    m_dwSearchTime: LongWord; 
    m_dwSearchTick: LongWord; 
 
    m_dwLatestHitTime: LongWord; 
    m_nHitTimeOverCount: LongWord; 
 
    m_szName: string[14]; 
 
    m_Ability: TOBJECTABILITY_RCD; 
    m_WAbility: TOBJECTABILITY_RCD;       //当前人物属性 
    m_AddAbility: TOBJECTADDABILITY_RCD; 
 
    m_nCharStatusEx: LongWord; 
    m_nCharStatus: LongWord; 
 
    m_sHitSpeed: SmallInt; 
 
    m_nHitDouble: Integer; 
 
    m_dwWalkTime: LongWord; 
 
    m_wStatusArr: array[0..MAX_STATUS_ATTRIBUTE - 1] of Word; 
    m_dwStatusTime: array[0..MAX_STATUS_ATTRIBUTE - 1] of LongWord; 
 
    m_btHitPlus: Byte; 
 
    m_btAntiMagic: Byte; 
    m_btHitPoint: Byte; 
    m_btSpeedPoint: Byte; 
    m_btAntiPoison: Byte; 
    m_btPoisonRecover: Byte; 
    m_btHealthRecover: Byte; 
    m_btSpellRecover: Byte; 
 
    m_fIsDead: Boolean; 
    m_dwDeathTime: LongWord; 
    m_fIsGhost: Boolean; 
    m_dwGhostTime: LongWord; 
 
    m_fOpenHealth: Boolean; 
    m_dwOpenHealthStart: LongWord; 
    m_dwOpenHealthTime: LongWord; 
    m_dwIncHealthSpellTime: LongWord; 
 
    m_dwHealthTick: LongWord; 
    m_dwSpellTick: LongWord; 
    m_dwTickSec: LongWord; 
 
    m_IncHealing: Word; 
    m_btPerHealing: Byte; 
    m_IncHealth: Word; 
    m_btPerHealth: Byte; 
    m_IncSpell: Word; 
    m_btPerSpell: Byte; 
 
    m_fAbilMagBubbleDefence: Boolean; 
    m_btMagBubbleDefenceLevel: Byte; 
 
    m_fInspector: Boolean; 
    m_fFastTrain: Boolean; 
    m_fHideMode: Boolean; 
    m_fIsNeverDie: Boolean; 
    m_fStoneMode: Boolean; 
    m_fStickMode: Boolean; 
    m_isUses: Boolean; 
    m_pMasterObject: TCharObject; 
    m_pTargetObject: TCharObject; 
    m_pLastHitterObject: TCharObject; 
    m_pExpHitterObject: TCharObject; 
 
    m_dwTargetFocusTime: LongWord; 
 
    m_fHumHideMode: Boolean; 
    m_fFixedHideMode: Boolean; 
 
    constructor Create(pUserInfo: TObject); 
    destructor Destroy; 
 
    function GetBackPosition(var nX, nY: Integer): Boolean; 
    function GetBack(nDirection: Integer): Integer; 
    procedure GetFrontPosition(var nX, nY: Integer); 
 
    procedure UpdateDelayProcessCheckParam1(pCharObject: TCharObject; wIdent, 
      wParam: Word; lParam1, lParam2, lParam3: LongWord; pszData: string; nDelay: 
      Integer); 
    procedure UpdateProcess(pCharObject: TCharObject; wIdent, wParam: Word; 
      lParam1, lParam2, lParam3: LongWord; pszData: string); 
    procedure AddProcess(pCharObject: TCharObject; wIdent, wParam: Word; 
      lParam1, lParam2, lParam3: LongWord; pszData: string); 
    procedure AddDelayProcess(pCharObject: TCharObject; wIdent, wParam: Word; 
      lParam1, lParam2, lParam3: LongWord; pszData: string; nDelay: Integer); 
    procedure AddRefMsg(wIdent, wParam: Word; lParam1, lParam2, lParam3: 
      LongWord; pszData: string); 
 
    function GetNextPosition(nDir, nDistance: Integer; var nX, nY: Integer): 
      Boolean; overload; 
    function GetNextPosition(nSX, nSY, nDir, nDistance: Integer; var nX, nY: 
      Integer): Boolean; overload; 
    function GetNextDirection(nTargetX, nTargetY: Integer): Integer; overload; 
    function GetNextDirection(nStartX, nStartY, nTargetX, nTargetY: Integer): 
      Integer; overload; 
 
    procedure UpdateVisibleObject(pCharObject: TCharObject); 
    procedure UpdateVisibleItem(nX, nY: Integer; pMapItem: PMAPITEM_RCD); 
    procedure UpdateVisibleEvent(pEvent: TObject); 
 
    procedure SelectTarget(pCharObject: TCharObject); 
 
    procedure IncHealthSpell(nHP, nMP: Integer); 
    procedure DamageSpell(nVal: Integer); 
    procedure DamageHealth(nDamage: Integer); 
    function GetMagStruckDamage(nDamage: Integer): Integer; 
    procedure StruckDamage(nDamage: Integer); 
    function GetHitStruckDamage(nDamage: Integer): Integer; 
    function GetAttackPower(nDamage, nVal: Integer): Integer; 
    function _Attack(wHitMode: Word; pCharObject: TCharObject): Boolean; 
 
    procedure WalkNextPos(nDir: Integer; var nX, nY: Integer); 
    procedure TurnTo(nDir: Integer); 
    function TurnXY(nX, nY, nDir: Integer): Boolean; 
    function WalkTo(nDir: Integer): Boolean; virtual; 
    function WalkXY(nX, nY, nDir: Integer): Boolean; 
    function RunTo(nDir: Integer): Boolean; 
    function RunXY(nX, nY, nDir: Integer): Boolean; 
    function HitXY(wIdent: Word; nX, nY, nDir, nHitStyle: Integer): Boolean; 
 
    procedure DoDamageWeapon(nDamage: Integer); 
 
    procedure Disappear; 
    procedure MakeGhost; 
 
    function DropItemDown(pItemRcd: PTCLIENTITEM; nRange: Integer; fIsGenItem: 
      Boolean): Boolean; 
 
    function AddCreatureSysop(nX, nY: Integer; pMonRaceInfo: PMONRACEINFO_RCD; 
      fSearch: Boolean): TCharObject; 
 
    procedure DoPushed(nDirection: Integer); 
    procedure DoMotaebo; 
    function CharPushed(nDir, nPushCount: Integer): Integer; 
 
    function DoShowHP(pCharObject: TCharObject; pMagicInfo: TObject; nLevel: 
      Integer): Boolean; 
    procedure MakeOpenHealth; 
    procedure BreakOpenHealth; 
    function MagPushArround(nPushLevel: Integer): Integer; 
    function MagPassThroughMagic(nStartX, nStartY, nTargetX, nTargetY, nDir, 
      nPwr: Integer; fUndeadAttack: Boolean): Integer; 
    function MagBubbleDefenceUp(nLevel, nSec: Integer): Boolean; 
    procedure DamageBubbleDefence; 
    function MagMakeFireCross(nDamage, nHTime, nX, nY: Integer): Integer; 
    function DirectAttack(pCharObject: TCharObject; nDamage: Integer): Boolean; 
    function SwordLongAttack(nDamage: Integer): Boolean; 
    function SwordWideAttack(nDamage: Integer): Boolean; 
    function MagBigExplosion(nPower, nX, nY, nWide: Integer): Boolean; 
    function MagBigHealing(nPower, nX, nY: Integer): Boolean; 
    function MagDefenceUp(nState, nSec: Integer): Boolean; 
    function MagMakeDefenceArea(nX, nY, nRange, nSec, nState: Integer): Boolean; 
    function MagElecBlizzard(nPower: Integer): Boolean; 
    function MagMakePrivateTransparent(nHTime: Integer): Boolean; 
    function MagMakeHolyCurtain(nHTime, nX, nY: Integer): Integer; 
    function MagMakeGroupTransparent(nX, nY, nHTime: Integer): Boolean; 
    function MagTurnUndead(pCharObject: TCharObject; nX, nY, nLevel: Integer): 
      Boolean; 
 
    function IsProperTarget(pCharObject: TCharObject): Boolean; virtual; 
    function IsFriend(pCharObject: TCharObject): Boolean; 
    function IsProperFriend(pCharObject: TCharObject): Boolean; 
 
    procedure SpaceMove(nX, nY: Integer; pMirMap: TObject); 
    procedure GoldChanged; 
    procedure HealthSpellChanged; 
 
    function GetAvailablePosition(pMirMap: TObject; var nX, nY: Integer; nRange: 
      Integer): Boolean; 
 
    procedure GetQueryUserName(pCharObject: TCharObject; nX, nY: Integer); 
 
    procedure SendSocket(lpDefMsg: PDEFAULTMESSAGE_RCD; pszPacket: string); 
 
    procedure Die; 
 
    function RestoreHealSpell: Boolean; 
 
    function GetCharStatus: LongWord; 
 
    function GetThisCharColor: Word; virtual; abstract; 
    procedure GetCharName(var pszCharName: string); virtual; abstract; 
    procedure Run; virtual; 
    procedure SearchViewRange; virtual; 
 
    function GetFrontObject: TCharObject; 
 
 
    procedure SysMsg(pszMsg: string; nMode: Integer); 
    function GetFeatureToLong: Integer; 
    function GetRPow(wPower: Word): Byte; 
  end; 
 
type 
  PPROCESSMSG_RCD = ^TPROCESSMSG_RCD; 
  TPROCESSMSG_RCD = record 
 
    wIdent: Word; 
    wParam: Word; 
    lParam1: LongWord; 
    lParam2: LongWord; 
    lParam3: LongWord; 
 
    dwDeliveryTime: LongWord; 
 
    pCharObject: TCharObject; 
 
    pszData: string; 
  end; 
 
type 
  TVisibleObject = class 
 
  public 
    nVisibleFlag: Integer; 
    pCharObject: TCharObject; 
  end; 
 
type 
  TVisibleEvent = class 
 
  public 
    nVisibleFlag: Integer; 
    pEvent: TObject; 
  end; 
 
type 
  TVisibleMapItem = class 
  public 
    nVisibleFlag: Integer; 
    wX: Word; 
    wY: Word; 
    pMapItem: PMAPITEM_RCD; 
  end; 
 
implementation 
 
uses UserInfo, DataHandler, GlobalDefinition, ObjectPlayer, ObjectEvent, 
  ObjectMonster, ProcessThreads, FunctionDeclaration, EDcode; 
//初始化 
 
constructor TCharObject.Create(pUserInfo: TObject); 
begin 
  m_pUserInfo := pUserInfo; 
 
  m_nCurrX := 0; 
  m_nCurrY := 0; 
 
  m_szName := ''; 
 
  m_dwHealthTick := 0; 
  m_dwSpellTick := 0; 
  m_dwTickSec := 0; 
 
  m_fOpenHealth := False; 
 
  m_nCharStatusEx := 0; 
  m_nCharStatus := 0; 
 
  m_IncHealing := 0; 
  m_IncHealth := 0; 
  m_IncSpell := 0; 
 
  m_btPerHealing := 5; 
  m_btPerHealth := 5; 
  m_btPerSpell := 5; 
 
  m_dwIncHealthSpellTime := 0; 
 
  m_dwTickSec := GetTickCount; 
 
  m_nEvent := -1; // No Event 
 
  m_sHitSpeed := 0; 
 
  m_fAbilMagBubbleDefence := False; 
  m_btMagBubbleDefenceLevel := 0; 
 
  m_fInspector := False; 
  m_fFastTrain := False; 
 
  m_IncHealth := 0; 
  m_IncSpell := 0; 
 
  m_fIsGhost := False; 
  m_fIsNeverDie := False; 
 
  m_btSpeedPoint := DEFSPEED; 
 
  m_fHumHideMode := False; 
  m_fFixedHideMode := False; 
 
  m_fStoneMode := False; 
  m_fStickMode := False; 
 
  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; 
  m_pMasterObject := nil; 
  m_pTargetObject := nil; 
  m_pLastHitterObject := nil; 
  m_pExpHitterObject := nil; 
end; 
 
destructor TCharObject.Destroy; 
begin 
  m_xVisibleItemList.Clear; 
  m_xVisibleItemList.Free; 
  m_xVisibleItemList := nil; 
end; 
//选中攻击目标 
 
procedure TCharObject.SelectTarget(pCharObject: TCharObject); 
begin 
  m_pTargetObject := pCharObject; 
  m_dwTargetFocusTime := GetTickCount; 
end; 
//得到下一个坐标位置 
 
procedure TCharObject.GetFrontPosition(var nX, nY: Integer); 
var 
  nHeight, nWidth: Integer; 
begin 
  nHeight := TMirMap(m_pMap).m_stMapFH.shHeight; 
  nWidth := TMirMap(m_pMap).m_stMapFH.shWidth; 
 
  nX := m_nCurrX; 
  nY := m_nCurrY; 
 
  case m_nDirection of 
    DR_UP: 
      begin 
        if nY > 0 then 
          Dec(nY); 
      end; 
    DR_DOWN: 
      begin 
        if nY < (nHeight - 1) then 
          Inc(nY); 
      end; 
    DR_LEFT: 
      begin 
        if nX > 0 then 
          Dec(nX); 
      end; 
    DR_RIGHT: 
      begin 
        if nX < (nWidth - 1) then 
          Inc(nX); 
      end; 
    DR_UPLEFT: 
      begin 
        if (nX > 0) and (nY > 0) then 
        begin 
          Dec(nX); 
          Dec(nY); 
        end; 
      end; 
    DR_UPRIGHT: 
      begin 
        if (nX > 0) and (nY < (nHeight - 1)) then 
        begin 
          Inc(nX); 
          Dec(nY); 
        end; 
      end; 
    DR_DOWNLEFT: 
      begin 
        if (nX < nWidth - 1) and (nY > 0) then 
        begin 
          Dec(nX); 
          Inc(nY); 
        end; 
      end; 
    DR_DOWNRIGHT: 
      begin 
        if (nX < (nWidth - 1)) and (nY < (nHeight - 1)) then 
        begin 
          Inc(nX); 
          Inc(nY); 
        end; 
      end; 
  end; 
end; 
//得到后退方向 
 
function TCharObject.GetBack(nDirection: Integer): Integer; 
begin 
  case nDirection of 
    DR_UP: 
      begin 
        Result := DR_DOWN; 
        Exit; 
      end; 
    DR_DOWN: 
      begin 
        Result := DR_UP; 
        Exit; 
      end; 
    DR_LEFT: 
      begin 
        Result := DR_RIGHT; 
        Exit; 
      end; 
    DR_RIGHT: 
      begin 
        Result := DR_LEFT; 
        Exit; 
      end; 
    DR_UPLEFT: 
      begin 
        Result := DR_DOWNRIGHT; 
        Exit; 
      end; 
    DR_UPRIGHT: 
      begin 
        Result := DR_DOWNLEFT; 
        Exit; 
      end; 
    DR_DOWNLEFT: 
      begin 
        Result := DR_UPRIGHT; 
        Exit; 
      end; 
    DR_DOWNRIGHT: 
      begin 
        Result := DR_UPLEFT; 
        Exit; 
      end; 
  end; 
  Result := nDirection; 
end; 
//得到后退坐标位置 
 
function TCharObject.GetBackPosition(var nX, nY: Integer): Boolean; 
var 
  nHeight, 
    nWidth: Integer; 
begin 
  nHeight := TMirMap(m_pMap).m_stMapFH.shHeight; 
  nWidth := TMirMap(m_pMap).m_stMapFH.shWidth; 
 
  nX := m_nCurrX; 
  nY := m_nCurrY; 
 
  case m_nDirection of 
    DR_UP: 
      begin 
        if nY < (nHeight - 1) then 
          Inc(nY); 
      end; 
    DR_DOWN: 
      begin 
        if nY > 0 then 
          Dec(nY); 
      end; 
    DR_LEFT: 
      begin 
        if nX < (nWidth - 1) then 
          Inc(nX); 
      end; 
    DR_RIGHT: 
      begin 
        if nX > 0 then 
          Dec(nY); 
      end; 
    DR_UPLEFT: 
      begin 
        if (nX < (nWidth - 1)) and (nY < (nHeight - 1)) then 
        begin 
          Inc(nX); 
          Inc(nY); 
        end; 
      end; 
    DR_UPRIGHT: 
      begin 
        if (nX < (nWidth - 1)) and (nY > 0) then 
        begin 
          Dec(nY); 
          Inc(nY); 
        end; 
      end; 
    DR_DOWNLEFT: 
      begin 
        if (nX > 0) and (nY < (nHeight - 1)) then 
        begin 
          Inc(nX); 
          Dec(nY); 
        end; 
      end; 
    DR_DOWNRIGHT: 
      begin 
        if (nX > 0) and (nY > 0) then 
        begin 
          Dec(nY); 
          Dec(nY); 
        end; 
      end; 
  end; 
  Result := True; 
end; 
//判断是否为正确的攻击对象,有待判断 
 
function TCharObject.IsProperTarget(pCharObject: TCharObject): Boolean; 
begin 
  Result := True; 
  if pCharObject.m_fIsDead then 
    Result := False; 
end; 
//判断是否为好友 
 
function TCharObject.IsFriend(pCharObject: TCharObject): Boolean; 
var 
  nAttackMode: Integer; 
begin 
  if (pCharObject.m_wObjectType and _OBJECT_HUMAN) > 0 then 
  begin 
    if pCharObject.m_pUserInfo <> nil then 
    begin 
      nAttackMode := TUserInfo(pCharObject.m_pUserInfo).GetAttackMode; 
      case nAttackMode of // 
        HAM_ALL: 
          begin 
            Result := True; 
            Exit; 
          end; 
        HAM_PEACE: 
          begin 
            Result := True; 
            Exit; 
          end; 
      end; // case 
    end; 
  end; 
  Result := False; 
end; 
 
{目标是不是朋友} 
function TCharObject.IsProperFriend(pCharObject: TCharObject): Boolean; 
var 
  fFlag: Boolean; 
begin 
  fFlag := False; 
 
  if pCharObject <> nil then 
  begin 
    if (m_wObjectType and _OBJECT_ANIMAL) > 0 then 
    begin 
      if (pCharObject.m_wObjectType and _OBJECT_ANIMAL) > 0 then 
        fFlag := True; 
      if pCharObject.m_pMasterObject <> nil then 
        fFlag := False; 
    end 
    else 
    begin 
      if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
      begin 
        fFlag := IsFriend(pCharObject); 
 
        if (pCharObject.m_wObjectType and _OBJECT_ANIMAL) > 0 then 
        begin 
          if pCharObject.m_pMasterObject = self then 
          begin 
            fFlag := True; 
          end 
          else if pCharObject.m_pMasterObject <> nil then 
          begin 
            fFlag := IsFriend(pCharObject.m_pMasterObject); 
          end; 
        end; 
      end 
      else 
      begin 
        fFlag := True; 
      end; 
    end; 
  end; 
  Result := fFlag; 
end; 
 
{获取角色状态} 
function TCharObject.GetCharStatus: LongWord; 
var 
  I: Integer; 
  s: LongWord; 
begin 
  s := 0; 
 
  for I := 0 to MAX_STATUS_ATTRIBUTE - 1 do 
  begin 
    if m_wStatusArr[I] > 0 then 
      s := s or ($80000000 shr I); 
  end; 
  Result := s or (m_nCharStatusEx and $000FFFFF); 
end; 
//重新计算生命值 
 
function TCharObject.RestoreHealSpell: Boolean; 
var 
  N, 
    nPlus: Integer; 
  fHealthSpellchanged: Boolean; 
  nHP, 
    nMP: Integer; 
  inchstime: LongWord; 
begin 
  if m_fIsNeverDie then 
  begin 
    m_WAbility.HP := m_WAbility.MaxHP; 
    m_WAbility.MP := m_WAbility.MaxMP; 
  end; 
 
  N := (GetTickCount - m_dwTickSec) div 20; //檬寸 50 
 
  m_dwTickSec := GetTickCount; 
 
  m_dwHealthTick := m_dwHealthTick + N; 
  m_dwSpellTick := m_dwSpellTick + N; 
 
  if not m_fIsDead then 
  begin 
    nPlus := 0; 
    fHealthSpellchanged := False; 
 
    if m_WAbility.HP < m_WAbility.MaxHP then 
    begin 
      if m_dwHealthTick >= HEALTHFILLTICK then 
      begin 
        nPlus := m_WAbility.MaxHP div 15 + 1; 
 
        if (m_WAbility.HP + nPlus) < m_WAbility.MaxHP then 
          m_WAbility.HP := m_WAbility.HP + nPlus 
        else 
          m_WAbility.HP := m_WAbility.MaxHP; 
 
        fHealthSpellchanged := True; 
      end; 
    end; 
 
    if m_WAbility.MP < m_WAbility.MaxMP then 
    begin 
      if m_dwSpellTick >= SPELLFILLTICK then 
      begin 
        nPlus := m_WAbility.MaxMP div 18 + 1; 
 
        if (m_WAbility.MP + nPlus) < m_WAbility.MaxMP then 
          m_WAbility.MP := m_WAbility.MP + nPlus 
        else 
          m_WAbility.MP := m_WAbility.MaxMP; 
 
        fHealthSpellchanged := True; 
      end; 
    end; 
 
    if m_WAbility.HP = 0 then 
    begin 
      Result := True; 
      Exit; 
    end; 
 
    if fHealthSpellchanged then 
      HealthSpellChanged; 
 
    if m_dwHealthTick >= HEALTHFILLTICK then 
      m_dwHealthTick := 0; 
    if m_dwSpellTick >= SPELLFILLTICK then 
      m_dwSpellTick := 0; 
  end 
  else 
  begin 
    if (GetTickCount - m_dwDeathTime) > (3 * 60 * 1000) then 
      MakeGhost; 
    Result := False; 
    Exit; 
  end; 
 
  if m_fIsDead and (m_IncSpell > 0) or (m_IncHealth > 0) or (m_IncHealing > 0) 
    then 
  begin 
    nHP := 0; 
    nMP := 0; 
 
    inchstime := 600 - Min(400, m_Ability.Level * 10); 
 
    if (GetTickCount - m_dwIncHealthSpellTime) >= inchstime then 
    begin 
      N := Min(200, (GetTickCount - m_dwIncHealthSpellTime) - inchstime); 
 
      m_dwIncHealthSpellTime := GetTickCount + N; 
 
      if (m_IncSpell > 0) or (m_IncHealth > 0) or (m_IncHealing > 0) then 
      begin 
        if m_btPerHealing <= 0 then 
          m_btPerHealing := 1; 
        if m_btPerSpell <= 0 then 
          m_btPerSpell := 1; 
        if m_btPerHealth <= 0 then 
          m_btPerHealth := 1; 
 
        if m_IncHealth < m_btPerHealth then 
        begin 
          nHP := nHP + m_IncHealth; 
          m_IncHealth := 0; 
        end 
        else 
        begin 
          nHP := nHP + m_btPerHealth; 
          m_IncHealth := m_IncHealth - m_btPerHealth; 
        end; 
 
        if m_IncSpell < m_btPerSpell then 
        begin 
          nMP := nMP + m_IncSpell; 
          m_IncSpell := 0; 
        end 
        else 
        begin 
          nHP := nHP + m_btPerSpell; 
          m_IncSpell := m_IncSpell - m_btPerSpell; 
        end; 
 
        if m_IncHealing < m_btPerHealing then 
        begin 
          nHP := nHP + m_IncHealing; 
          m_IncHealing := 0; 
        end 
        else 
        begin 
          nHP := nHP + m_btPerHealing; 
          m_IncHealing := m_IncHealing - m_btPerHealing; 
        end; 
      end; 
 
      m_btPerHealing := 5; 
      m_btPerHealth := 5 + (m_Ability.Level div 10); 
      m_btPerSpell := 5 + (m_Ability.Level div 10); 
 
      IncHealthSpell(nHP, nMP); 
 
      if m_WAbility.HP = m_WAbility.MaxHP then 
      begin 
        m_IncHealth := 0; 
        m_IncHealing := 0; 
      end; 
 
      if m_WAbility.MP = m_WAbility.MaxMP then 
        m_IncSpell := 0; 
    end; 
  end 
  else 
    m_dwIncHealthSpellTime := GetTickCount; 
 
  if Integer(m_dwHealthTick) < -HEALTHFILLTICK then 
  begin 
    if m_WAbility.HP > 1 then 
    begin 
      Dec(m_WAbility.HP); 
      m_dwHealthTick := m_dwHealthTick + HEALTHFILLTICK; 
 
      HealthSpellChanged; 
    end; 
  end; 
 
  Result := False; 
end; 
//丢弃物品 
 
function TCharObject.DropItemDown(pItemRcd: PTCLIENTITEM; nRange: Integer; 
  fIsGenItem: Boolean): Boolean; 
var 
  xpMapItem: PMAPITEM_RCD; 
  lptGenItemRcd: PGENERALITEM_RCD; 
  nX, nY: Integer; 
begin 
  New(xpMapItem); 
  xpMapItem^.nCount := 1; 
 
  if fIsGenItem then 
  begin 
 
 
    xpMapItem^.wLooks := Word(g_pStdItemEtc[lptGenItemRcd^.nStdIndex].dwLooks); 
    xpMapItem^.btAniCount := Byte(0); 
 
    xpMapItem^.pItem := Integer(pItemRcd); 
 
    xpMapItem^.szName := g_pStdItemEtc[lptGenItemRcd^.nStdIndex].szName; 
  end 
  else 
  begin 
    xpMapItem^.wLooks := pItemRcd^.s.Looks; 
    xpMapItem^.btAniCount := Byte(pItemRcd^.s.Looks); 
 
    xpMapItem^.pItem := Integer(pItemRcd); 
 
 
    xpMapItem^.szName := pItemRcd^.s.Name; 
  end; 
 
  TMirMap(m_pMap).GetDropPosition(m_nCurrX, m_nCurrY, nRange, nX, nY); 
  TMirMap(m_pMap).AddNewObject(nX, nY, OS_ITEMOBJECT, Pointer(xpMapItem)); 
 
  AddRefMsg(RM_ITEMSHOW, xpMapItem^.wLooks, Integer(xpMapItem), nX, nY, 
    xpMapItem^.szName); 
 
  Result := True; 
end; 
 
procedure TCharObject.Run; 
var 
  I: Integer; 
  fChg, fNeedRecalc: Boolean; 
begin 
  if m_fOpenHealth then 
  begin 
    if (GetTickCount - m_dwOpenHealthStart) > m_dwOpenHealthTime then 
      BreakOpenHealth; 
  end; 
 
  fChg := False; 
  fNeedRecalc := False; 
 
  for I := 0 to MAX_STATUS_ATTRIBUTE - 1 do // Iterate 
  begin 
    if (m_wStatusArr[I] > 0) and (m_wStatusArr[I] < 60000) then 
    begin 
      if (GetTickCount - m_dwStatusTime[I]) > 1000 then 
      begin 
        Dec(m_wStatusArr[I]); 
        m_dwStatusTime[I] := m_dwStatusTime[I] + 1000; 
 
        if m_wStatusArr[I] = 0 then 
        begin 
          fChg := True; 
          case I of // 
            STATE_DEFENCEUP: 
              begin 
                fNeedRecalc := True; 
                SysMsg('SysMsg1', 1); 
              end; 
            STATE_MAGDEFENCEUP: 
              begin 
                fNeedRecalc := True; 
                SysMsg('SysMsg2', 1); 
              end; 
            STATE_BUBBLEDEFENCEUP: 
              begin 
                m_fAbilMagBubbleDefence := False; 
              end; 
          end; // case 
        end; 
      end; 
    end; 
  end; // for 
 
  if fChg then 
  begin 
    m_nCharStatus := GetCharStatus; 
    AddRefMsg(RM_CHARSTATUSCHANGED, m_sHitSpeed, m_nCharStatus, 0, 0, ''); 
  end; 
 
  if fNeedRecalc then 
  begin 
    TPlayerObject(self).RecalcAbilitys; 
    AddProcess(self, RM_ABILITY, 0, 0, 0, 0, ''); 
  end; 
end; 
 
procedure TCharObject.Die; 
begin 
  if m_fIsNeverDie then 
    Exit; 
 
  m_IncHealing := 0; 
  m_IncHealth := 0; 
  m_IncSpell := 0; 
 
  m_dwDeathTime := GetTickCount; 
 
  if (m_wObjectType <> _OBJECT_NPC) then 
    AddRefMsg(RM_DEATH, m_nDirection, m_nCurrX, m_nCurrY, 1, ''); 
 
  m_fIsDead := True; 
end; 
 
//获得可以活动的位置 
function TCharObject.GetAvailablePosition(pMirMap: TObject; var nX, nY: Integer; 
  nRange: Integer): Boolean; 
var 
  I: Integer; 
  nOrgX, 
    nOrgY, 
    nLoonCnt: Integer; 
begin 
  if TMirMap(pMirMap).CanMove(nX, nY) then 
  begin 
    Result := True; 
    Exit; 
  end; 
 
  nOrgX := nX; 
  nOrgY := nY; 
  nLoonCnt := (4 * nRange) * (nRange + 1); 
 
  for I := 0 to nLoonCnt - 1 do // Iterate 
  begin 
    nX := nOrgX + RandomRange(-2, 2); 
    nY := nOrgY + RandomRange(-2, 2); 
 
    if TMirMap(pMirMap).CanMove(nX, nY) then 
    begin 
      Result := True; 
      Exit; 
    end; 
  end; // for 
 
  nX := nOrgX; 
  nY := nOrgY; 
 
  Result := False; 
end; 
 
function TCharObject.GetNextPosition(nDir, nDistance: Integer; var nX, nY: 
  Integer): Boolean; 
begin 
  Result := GetNextPosition(m_nCurrX, m_nCurrY, nDir, nDistance, nX, nY); 
end; 
 
 
function TCharObject.GetNextPosition(nSX, nSY, nDir, nDistance: Integer; var nX, 
  nY: Integer): Boolean; 
begin 
  nX := nSX; 
  nY := nSY; 
 
  case nDir of // 
    DR_UP: 
      begin 
        if nY > (nDistance - 1) then 
        begin 
          nY := nY - nDistance; 
        end; 
      end; 
    DR_DOWN: 
      begin 
        if nY < (TMirMap(m_pMap).m_stMapFH.shHeight - nDistance) then 
        begin 
          nY := nY + nDistance; 
        end; 
      end; 
    DR_LEFT: 
      begin 
        if nX > (nDistance - 1) then 
        begin 
          nX := nX - nDistance; 
        end; 
      end; 
    DR_RIGHT: 
      begin 
        if nX < (TMirMap(m_pMap).m_stMapFH.shWidth - nDistance) then 
        begin 
          nX := nX + nDistance; 
        end; 
      end; 
    DR_UPLEFT: 
      begin 
        if (nX > (nDistance - 1)) and (nY > (nDistance - 1)) then 
        begin 
          nX := nX - nDistance; 
          nY := nY - nDistance; 
        end; 
      end; 
    DR_UPRIGHT: 
      begin 
        if (nX > (nDistance - 1)) and (nY < (TMirMap(m_pMap).m_stMapFH.shHeight 
          - nDistance)) then 
        begin 
          nX := nX + nDistance; 
          nY := nY - nDistance; 
        end; 
      end; 
    DR_DOWNLEFT: 
      begin 
        if (nX < (TMirMap(m_pMap).m_stMapFH.shWidth - nDistance)) and (nY > 
          (nDistance - 1)) then 
        begin 
          nX := nX - nDistance; 
          nY := nY + nDistance; 
        end; 
      end; 
    DR_DOWNRIGHT: 
      begin 
        if (nX < (TMirMap(m_pMap).m_stMapFH.shWidth - nDistance)) and (nY < 
          (TMirMap(m_pMap).m_stMapFH.shHeight - nDistance)) then 
        begin 
          nX := nX + nDistance; 
          nY := nY + nDistance; 
        end; 
      end; 
  end; // case 
 
  if (m_nCurrX = nX) and (m_nCurrY = nY) then 
    Result := False; 
 
  Result := True; 
end; 
 
function TCharObject.GetNextDirection(nTargetX, nTargetY: Integer): Integer; 
begin 
  Result := GetNextDirection(m_nCurrX, m_nCurrY, nTargetX, nTargetY); 
end; 
 
function TCharObject.GetNextDirection(nStartX, nStartY, nTargetX, nTargetY: 
  Integer): Integer; 
var 
  nFlagX, 
    nFlagY: Integer; 
begin 
  if nStartX < nTargetX then 
    nFlagX := 1 
  else if nStartX = nTargetX then 
    nFlagX := 0 
  else 
    nFlagX := -1; 
 
  if abs(nStartY - nTargetY) > 2 then 
    if (nStartY >= (nTargetY - 1)) and (nStartY <= (nTargetY + 1)) then 
      nFlagX := 0; 
 
  if nStartY < nTargetY then 
    nFlagY := 1 
  else if nStartY = nTargetY then 
    nFlagY := 0 
  else 
    nFlagY := -1; 
 
  if abs(nStartX - nTargetX) > 2 then 
    if (nStartX >= (nTargetX - 1)) and (nStartX <= (nTargetX + 1)) then 
      nFlagY := 0; 
 
  if (nFlagX = 0) and (nFlagY = -1) then 
  begin 
    Result := DR_UP; 
    Exit; 
  end 
  else if (nFlagX = 1) and (nFlagY = -1) then 
  begin 
    Result := DR_UPRIGHT; 
    Exit; 
  end 
  else if (nFlagX = 1) and (nFlagY = 0) then 
  begin 
    Result := DR_RIGHT; 
    Exit; 
  end 
  else if (nFlagX = 1) and (nFlagY = 1) then 
  begin 
    Result := DR_DOWNRIGHT; 
    Exit; 
  end 
  else if (nFlagX = 0) and (nFlagY = 1) then 
  begin 
    Result := DR_DOWN; 
    Exit; 
  end 
  else if (nFlagX = -1) and (nFlagY = 1) then 
  begin 
    Result := DR_DOWNLEFT; 
    Exit; 
  end 
  else if (nFlagX = -1) and (nFlagY = 0) then 
  begin 
    Result := DR_LEFT; 
    Exit; 
  end 
  else if (nFlagX = -1) and (nFlagY = -1) then 
  begin 
    Result := DR_UPLEFT; 
    Exit; 
  end; 
 
  Result := DR_DOWN; 
end; 
 
function TCharObject.GetFrontObject: TCharObject; 
var 
  nX, 
    nY: Integer; 
  pCharObject: TCharObject; 
begin 
  GetFrontPosition(nX, nY); 
 
  pCharObject := TCharObject(TMirMap(m_pMap).GetObject(nX, nY)); 
 
  if pCharObject <> nil then 
  begin 
    Result := pCharObject; 
    Exit; 
  end; 
  Result := nil; 
end; 
 
procedure TCharObject.UpdateDelayProcessCheckParam1(pCharObject: TCharObject; 
  wIdent, wParam: Word; lParam1, lParam2, lParam3: LongWord; pszData: string; 
  nDelay: Integer); 
var 
  I: Integer; 
  nCount: Integer; 
  lpProcessMsg: PPROCESSMSG_RCD; 
begin 
  nCount := m_DelayProcessQ.COunt; 
 
  for I := 0 to nCount - 1 do // Iterate 
  begin 
    lpProcessMsg := PPROCESSMSG_RCD(m_DelayProcessQ.Pop); 
    if lpProcessMsg <> nil then 
    begin 
      if (lpProcessMsg^.wIdent = wIdent) and (lpProcessMsg^.lParam1 = lParam1) 
        then 
      begin 
        if lpProcessMsg^.pszData <> '' then 
        begin 
          lpProcessMsg^.pszData := ''; 
        end; 
        lpProcessMsg := nil; 
      end 
      else 
      begin 
        m_DelayProcessQ.Push(lpProcessMsg); 
      end; 
    end; 
  end; // for 
 
  AddDelayProcess(pCharObject, wIdent, wParam, lParam1, lParam2, lParam3, 
    pszData, nDelay); 
end; 
 
procedure TCharObject.UpdateProcess(pCharObject: TCharObject; wIdent, wParam: 
  Word; lParam1, lParam2, lParam3: LongWord; pszData: string); 
var 
  I, 
    nCount: Integer; 
  lpProcessMsg: PPROCESSMSG_RCD; 
begin 
  nCount := m_ProcessQ.COunt; 
 
  for I := 0 to nCount - 1 do // Iterate 
  begin 
    lpProcessMsg := PPROCESSMSG_RCD(m_ProcessQ.Pop); 
    if lpProcessMsg <> nil then 
    begin 
      if lpProcessMsg^.wIdent = wIdent then 
      begin 
        if lpProcessMsg^.pszData <> '' then 
        begin 
          lpProcessMsg^.pszData := ''; 
        end; 
        lpProcessMsg := nil; 
      end 
      else 
      begin 
        m_ProcessQ.Push(lpProcessMsg); 
      end; 
    end; 
  end; // for 
  AddProcess(pCharObject, wIdent, wParam, lParam1, lParam2, lParam3, pszData); 
end; 
 
procedure TCharObject.AddProcess(pCharObject: TCharObject; wIdent, wParam: Word; 
  lParam1, lParam2, lParam3: LongWord; pszData: string); 
var 
  lpProcessMsg: PPROCESSMSG_RCD; 
begin 
  New(lpProcessMsg); 
  if not m_fIsGhost then 
  begin 
    if lpProcessMsg <> nil then 
    begin 
      lpProcessMsg^.wIdent := wIdent; 
      lpProcessMsg^.wParam := wParam; 
      lpProcessMsg^.lParam1 := lParam1; 
      lpProcessMsg^.lParam2 := lParam2; 
      lpProcessMsg^.lParam3 := lParam3; 
 
      lpProcessMsg^.dwDeliveryTime := 0; 
 
      lpProcessMsg^.pCharObject := pCharObject; 
 
      if pszData <> '' then 
      begin 
        lpProcessMsg^.pszData := pszData; 
      end; 
      if m_ProcessQ = nil then 
        m_ProcessQ := TQueue.Create; 
      m_ProcessQ.Push(lpProcessMsg); 
    end; 
  end; 
end; 
 
procedure TCharObject.AddDelayProcess(pCharObject: TCharObject; wIdent, wParam: 
  Word; lParam1, lParam2, lParam3: LongWord; pszData: string; nDelay: Integer); 
var 
  lpProcessMsg: PPROCESSMSG_RCD; 
begin 
  New(lpProcessMsg); 
 
  if lpProcessMsg <> nil then 
  begin 
    lpProcessMsg^.wIdent := wIdent; 
    lpProcessMsg^.wParam := wParam; 
    lpProcessMsg^.lParam1 := lParam1; 
    lpProcessMsg^.lParam2 := lParam2; 
    lpProcessMsg^.lParam3 := lParam3; 
 
    lpProcessMsg^.dwDeliveryTime := GetTickCount + nDelay; 
 
    lpProcessMsg^.pCharObject := pCharObject; 
 
    if pszData <> '' then 
    begin 
      lpProcessMsg^.pszData := pszData; 
    end; 
 
    m_DelayProcessQ.Push(lpProcessMsg); 
  end; 
end; 
 
procedure TCharObject.AddRefMsg(wIdent, wParam: Word; lParam1, lParam2, lParam3: 
  LongWord; pszData: string); 
var 
  pMapCellInfo: PMAPCELLINFO_RCD; 
  pCharObject: TCharObject; 
  pOSObject: POSOBJECT_RCD; 
  I, X, Y, 
    nStartX, nEndX, 
    nStartY, nEndY, COunt: Integer; 
begin 
 
 
  pMapCellInfo := nil; 
  pCharObject := nil; 
 
  nStartX := m_nCurrX - _RANGE_X; 
  nEndX := m_nCurrX + _RANGE_X; 
  nStartY := m_nCurrY - _RANGE_Y; 
  nEndY := m_nCurrY + _RANGE_Y; 
 
  if m_fInspector then 
    Exit; 
  if m_xCacheObjectList = nil then 
    m_xCacheObjectList := TThreadList.Create; 
 
  COunt := m_xCacheObjectList.LockList.COunt; 
  m_xCacheObjectList.UnlockList; 
  if ((GetTickCount - m_dwCacheTick) > _CACHE_TICK) or (COunt = 0) then 
  begin 
    m_xCacheObjectList.Clear; 
    for X := nStartX to nEndX do 
    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 
          begin 
            with pMapCellInfo^.m_xpObjectList.LockList do 
            begin 
              for I := 0 to Count - 1 do // Iterate 
              begin 
                pOSObject := items[I]; 
                if pOSObject^.btType = OS_MOVINGOBJECT then 
                begin 
                  pCharObject := TCharObject(pOSObject^.pObject); 
                  if not pCharObject.m_fIsGhost then 
                  begin 
                    if (pCharObject.m_wObjectType and _OBJECT_HUMAN) > 0 then 
                    begin 
                      pCharObject.AddProcess(self, wIdent, wParam, lParam1, 
                        lParam2, lParam3, pszData); 
                      m_xCacheObjectList.Add(pCharObject); 
                    end; 
                  end; 
                end; 
              end; // for 
            end; // with 
            pMapCellInfo^.m_xpObjectList.UnlockList; 
          end; 
        end; // if (pMapCellInfo) 
 
      end; // for (y) 
    end; // for (x) 
 
    m_dwCacheTick := GetTickCount; 
  end 
  else 
  begin 
    with m_xCacheObjectList.LockList do 
    begin 
      for I := 0 to COunt - 1 do // Iterate 
      begin 
        pCharObject := items[I]; 
        if not pCharObject.m_fIsGhost then 
        begin 
          if (pCharObject.m_pMap = m_pMap) and 
            (abs(pCharObject.m_nCurrX - m_nCurrX) <= 11) and 
            (abs(pCharObject.m_nCurrY - m_nCurrY) <= 11) then 
          begin 
            if (pCharObject.m_wObjectType and _OBJECT_HUMAN) > 0 then 
            begin 
              pCharObject.AddProcess(self, wIdent, wParam, lParam1, lParam2, 
                lParam3, pszData); 
            end; 
          end; 
        end; 
      end; // for 
    end; // with 
    m_xCacheObjectList.UnlockList; 
  end; 
end; 
 
procedure TCharObject.SpaceMove(nX, nY: Integer; pMirMap: TObject); 
begin 
  if TMirMap(m_pMap).RemoveObject(m_nCurrX, m_nCurrY, OS_MOVINGOBJECT, self) 
    then 
  begin 
    if m_xVisibleItemList <> nil then 
    begin 
      m_xVisibleItemList.Clear; 
      m_xVisibleItemList := nil; 
    end; 
 
    m_pMap := pMirMap; 
 
    m_nCurrX := nX; 
    m_nCurrY := nY; 
 
    if TMirMap(m_pMap).AddNewObject(m_nCurrX, m_nCurrY, OS_MOVINGOBJECT, self) 
      then 
    begin 
      AddProcess(self, RM_CLEAROBJECTS, 0, 0, 0, 0, ''); 
      AddProcess(self, RM_CHANGEMAP, 0, 0, 0, 0, ''); 
 
      AddRefMsg(RM_SPACEMOVE_SHOW, m_nDirection, m_nCurrX, m_nCurrY, 0, ''); 
    end; 
  end; 
 
  end; 
 
procedure TCharObject.UpdateVisibleObject(pCharObject: TCharObject); 
var 
  I: Integer; 
  pVisibleObject, 
    pNewVisibleObject: TVisibleObject; 
begin 
 
 
  with m_xVisibleObjectList.LockList do 
  begin 
    for I := 0 to COunt - 1 do // Iterate 
    begin 
      pVisibleObject := items[I]; 
      if pVisibleObject.pCharObject = pCharObject then 
      begin 
        pVisibleObject.nVisibleFlag := 1; 
        m_xVisibleObjectList.UnlockList; 
        Exit; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleObjectList.UnlockList; 
 
  pNewVisibleObject := TVisibleObject.Create; 
 
  pNewVisibleObject.nVisibleFlag := 2; 
  pNewVisibleObject.pCharObject := pCharObject; 
 
  m_xVisibleObjectList.Add(pNewVisibleObject); 
end; 
 
procedure TCharObject.UpdateVisibleItem(nX, nY: Integer; pMapItem: 
  PMAPITEM_RCD); 
var 
  I: Integer; 
  pVisibleNewItem, 
    pVisibleItem: TVisibleMapItem; 
begin 
  with m_xVisibleItemList.LockList do 
  begin 
    for I := 0 to COunt - 1 do // Iterate 
    begin 
      pVisibleItem := items[I]; 
      if pVisibleItem.pMapItem = pMapItem then 
      begin 
        pVisibleItem.nVisibleFlag := 1; 
        m_xVisibleItemList.UnlockList; 
        Exit; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleItemList.UnlockList; 
 
  pVisibleNewItem := TVisibleMapItem.Create; 
  pVisibleNewItem.nVisibleFlag := 2; 
  pVisibleNewItem.wX := Word(nX); 
  pVisibleNewItem.wY := Word(nY); 
  pVisibleNewItem.pMapItem := pMapItem; 
 
  m_xVisibleItemList.Add(pVisibleNewItem); 
end; 
 
procedure TCharObject.UpdateVisibleEvent(pEvent: TObject); 
var 
  I: Integer; 
  pVisibleEvent, 
    pVisibleNewEvent: TVisibleEvent; 
begin 
  with m_xVisibleEventList.LockList do 
  begin 
    for I := 0 to COunt - 1 do // Iterate 
    begin 
      pVisibleEvent := TVisibleEvent(items[I]); 
      if pVisibleEvent.pEvent = pEvent then 
      begin 
        pVisibleEvent.nVisibleFlag := 1; 
        m_xVisibleEventList.UnlockList; 
        Exit; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleEventList.UnlockList; 
 
  pVisibleNewEvent := TVisibleEvent.Create; 
 
  pVisibleNewEvent.nVisibleFlag := 2; 
  pVisibleNewEvent.pEvent := pEvent; 
 
  m_xVisibleEventList.Add(pVisibleNewEvent); 
end; 
 
procedure TCharObject.SearchViewRange; 
var 
  I: Integer; 
  X, Y: Integer; 
  nStartX, nEndX, 
    nStartY, nEndY: Integer; 
  pMapCellInfo: PMAPCELLINFO_RCD; 
  pOSObject: POSOBJECT_RCD; 
  pCharObject: TCharObject; 
  pEvent: TEvent; 
  pVisibleObject: TVisibleObject; 
  pVisibleItem: TVisibleMapItem; 
  pVisibleEvent: TVisibleEvent; 
begin 
 
  nStartX := m_nCurrX - m_nViewRange; 
  nEndX := m_nCurrX + m_nViewRange; 
  nStartY := m_nCurrY - m_nViewRange; 
  nEndY := m_nCurrY + m_nViewRange; 
 
  // Clear VisibleObjectList 
  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; 
 
  // Clear VisibleMapItem 
  with m_xVisibleItemList.LockList do 
  begin 
    for I := 0 to COunt - 1 do // Iterate 
    begin 
      pVisibleItem := items[I]; 
      if pVisibleItem <> nil then 
      begin 
        pVisibleItem.nVisibleFlag := 0; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleItemList.UnlockList; 
 
  // Clear VisibleEvent 
  with m_xVisibleEventList.LockList do 
  begin 
    for I := 0 to COunt - 1 do // Iterate 
    begin 
      pVisibleEvent := items[I]; 
      if pVisibleEvent <> nil then 
      begin 
        pVisibleEvent.nVisibleFlag := 0; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleEventList.UnlockList; 
 
  // Search VisibleAllObjectList 
  for X := nStartX to nEndX do // Iterate 
  begin 
    for Y := nStartY to nEndY do // Iterate 
    begin 
      pMapCellInfo := TMirMap(m_pMap).GetMapCellInfo(X, Y); 
      if pMapCellInfo <> nil then 
      begin 
        if pMapCellInfo^.m_xpObjectList <> nil then 
        begin 
          with pMapCellInfo^.m_xpObjectList.LockList do 
          begin 
            for I := COunt - 1 downto 0 do // Iterate 
            begin 
              pOSObject := items[I]; 
              if pOSObject <> nil then 
              begin 
                if pOSObject^.btType = OS_MOVINGOBJECT then 
                begin 
                  pCharObject := TCharObject(pOSObject^.pObject); 
                  if (not pCharObject.m_fInspector) and (not 
                    pCharObject.m_fIsGhost) and (not pCharObject.m_fHideMode) then 
                  begin 
                    UpdateVisibleObject(pCharObject); 
                  end; 
                end 
                else if pOSObject^.btType = OS_ITEMOBJECT then 
                begin 
                  if (GetTickCount - pOSObject^.dwAddTime) > 60 * 60 * 1000 then 
                  begin 
                    FreeMem(pOSObject); 
                    pOSObject := nil; 
                    Delete(I); 
                    Continue; 
                  end 
                  else 
                  begin 
                    UpdateVisibleItem(X, Y, PMAPITEM_RCD(pOSObject^.pObject)); 
                  end; 
                end 
                else if pOSObject^.btType = OS_EVENTOBJECT then 
                begin 
                  pEvent := TEvent(pOSObject^.pObject); 
                  if pEvent.m_fVisible then 
                  begin 
                    UpdateVisibleEvent(pEvent); 
                  end; 
                end; 
              end; 
            end; // for 
          end; // with 
          pMapCellInfo.m_xpObjectList.UnlockList; 
        end; 
      end; 
    end; // for Y 
  end; // for X 
 
  with m_xVisibleObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pVisibleObject := items[I]; 
      if pVisibleObject <> nil then 
      begin 
        if pVisibleObject.nVisibleFlag = 0 then 
        begin 
          if pVisibleObject.pCharObject.m_fHideMode then 
          begin 
            AddProcess(pVisibleObject.pCharObject, RM_DISAPPEAR, 0, 0, 0, 0, 
              ''); 
 
            pVisibleObject.Free; 
            pVisibleObject := nil; 
            Delete(I); 
            Continue; 
          end; 
        end 
        else 
        begin 
          if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
          begin 
            if pVisibleObject.nVisibleFlag = 2 then 
            begin 
              if pVisibleObject.pCharObject <> self then 
              begin 
                if pVisibleObject.pCharObject.m_fIsDead then 
                begin 
                  AddProcess(pVisibleObject.pCharObject, RM_DEATH, 
                    pVisibleObject.pCharObject.m_nDirection, 
                    pVisibleObject.pCharObject.m_nCurrX, 
                      pVisibleObject.pCharObject.m_nCurrY, 0, ''); 
                end 
                else 
                begin 
                  AddProcess(pVisibleObject.pCharObject, RM_TURN, 
                    pVisibleObject.pCharObject.m_nDirection, 
                    pVisibleObject.pCharObject.m_nCurrX, 
                      pVisibleObject.pCharObject.m_nCurrY, 0, 
                      pVisibleObject.pCharObject.m_szName); 
                end; 
              end; 
              pVisibleObject.nVisibleFlag := 1; 
            end; 
          end; 
        end; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleObjectList.UnlockList; 
 
  // Update Map Item 
  with m_xVisibleItemList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pVisibleItem := items[I]; 
      if pVisibleItem <> nil then 
      begin 
        if pVisibleItem.nVisibleFlag = 0 then 
        begin 
          AddProcess(self, RM_ITEMHIDE, 0, Integer(pVisibleItem.pMapItem), 
            pVisibleItem.wX, pVisibleItem.wY, ''); 
 
          pVisibleItem.Free; 
          pVisibleItem := nil; 
          Delete(I); 
          Continue; 
        end 
        else 
        begin 
          if pVisibleItem.nVisibleFlag = 2 then 
          begin 
            AddProcess(self, RM_ITEMSHOW, pVisibleItem.pMapItem^.wLooks, 
              Integer(pVisibleItem.pMapItem), 
              pVisibleItem.wX, pVisibleItem.wY, pVisibleItem.pMapItem^.szName); 
            pVisibleItem.nVisibleFlag := 1; 
          end; 
        end; 
      end; 
    end; // for 
  end; // with 
  m_xVisibleItemList.UnlockList; 
 
  // Update Event Item 
  with m_xVisibleEventList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pVisibleEvent := items[I]; 
      if pVisibleEvent.nVisibleFlag = 0 then 
      begin 
        AddProcess(self, RM_HIDEEVENT, 0, Integer(pVisibleEvent.pEvent), 
          TEvent(pVisibleEvent.pEvent).m_nX, TEvent(pVisibleEvent.pEvent).m_nY, 
          ''); 
 
        pVisibleEvent.Free; 
        pVisibleEvent := nil; 
        Delete(I); 
        Continue; 
      end 
      else if pVisibleEvent.nVisibleFlag = 2 then 
      begin 
        AddProcess(self, RM_SHOWEVENT, 
          TEvent(pVisibleEvent.pEvent).m_nEventType, 
          Integer(pVisibleEvent.pEvent), 
          MAKELONG(TEvent(pVisibleEvent.pEvent).m_nX, 
            TEvent(pVisibleEvent.pEvent).m_nEventParam), 
            TEvent(pVisibleEvent.pEvent).m_nY, ''); 
      end; 
    end; // for 
  end; // with 
  m_xVisibleEventList.UnlockList; 
end; 
 
procedure TCharObject.Disappear; 
begin 
  if m_pMap <> nil then 
  begin 
    TMirMap(m_pMap).RemoveObject(m_nCurrX, m_nCurrY, OS_MOVINGOBJECT, self); 
    AddRefMsg(RM_DISAPPEAR, 0, 0, 0, 0, ''); 
  end; 
end; 
 
procedure TCharObject.MakeGhost; 
begin 
  m_fIsGhost := True; 
  m_dwGhostTime := GetTickCount; 
 
  Disappear; 
end; 
 
procedure TCharObject.TurnTo(nDir: Integer); 
begin 
  AddRefMsg(RM_TURN, nDir, m_nCurrX, m_nCurrY, 0, m_szName); 
  m_nDirection := nDir; 
end; 
 
function TCharObject.TurnXY(nX, nY, nDir: Integer): Boolean; 
begin 
  if (m_nCurrX = nX) and (m_nCurrY = nY) then 
  begin 
    AddRefMsg(RM_TURN, nDir, m_nCurrX, m_nCurrY, 0, m_szName); 
    m_nDirection := nDir; 
    Result := True; 
    Exit; 
  end; 
  Result := False; 
end; 
 
procedure TCharObject.WalkNextPos(nDir: Integer; var nX, nY: Integer); 
begin 
  case nDir of // 
    DR_UP: 
      begin 
        nX := m_nCurrX; 
        nY := m_nCurrY - 1; 
      end; 
    DR_UPRIGHT: 
      begin 
        nX := m_nCurrX + 1; 
        nY := m_nCurrY - 1; 
      end; 
    DR_RIGHT: 
      begin 
        nX := m_nCurrX + 1; 
        nY := m_nCurrY; 
      end; 
    DR_DOWNRIGHT: 
      begin 
        nX := m_nCurrX + 1; 
        nY := m_nCurrY + 1; 
      end; 
    DR_DOWN: 
      begin 
        nX := m_nCurrX; 
        nY := m_nCurrY + 1; 
      end; 
    DR_DOWNLEFT: 
      begin 
        nX := m_nCurrX - 1; 
        nY := m_nCurrY + 1; 
      end; 
    DR_LEFT: 
      begin 
        nX := m_nCurrX - 1; 
        nY := m_nCurrY; 
      end; 
    DR_UPLEFT: 
      begin 
        nX := m_nCurrX - 1; 
        nY := m_nCurrY - 1; 
      end; 
  end; // case 
end; 
 
function TCharObject.WalkTo(nDir: Integer): Boolean; 
var 
  nX, nY: Integer; 
  fResult: Boolean; 
begin 
  WalkNextPos(nDir, nX, nY); 
 
  fResult := WalkXY(nX, nY, nDir); 
 
  if fResult then 
  begin 
    if m_fFixedHideMode then 
    begin 
      if m_fHumHideMode then 
      begin 
        m_wStatusArr[STATE_TRANSPARENT] := 1; 
      end; 
    end; 
  end; 
 
  Result := fResult; 
end; 
 
function TCharObject.RunTo(nDir: Integer): Boolean; 
var 
  I: Integer; 
  nX, nY, nWalk: Integer; 
begin 
  nX := m_nCurrX; 
  nY := m_nCurrY; 
  nWalk := 2; 
 
  if m_tFeatureEx.btHorse > 0 then 
  begin 
    nWalk := 3; 
  end; 
 
  for I := 0 to nWalk - 1 do // Iterate 
  begin 
    case nDir of // 
      DR_UP: 
        begin 
          Dec(nY); 
        end; 
      DR_UPRIGHT: 
        begin 
          Inc(nX); 
          Dec(nY); 
        end; 
      DR_RIGHT: 
        begin 
          Inc(nX); 
        end; 
      DR_DOWNRIGHT: 
        begin 
          Inc(nX); 
          Inc(nY); 
        end; 
      DR_DOWN: 
        begin 
          Inc(nY); 
        end; 
      DR_DOWNLEFT: 
        begin 
          Dec(nX); 
          Inc(nY); 
        end; 
      DR_LEFT: 
        begin 
          Dec(nX); 
        end; 
      DR_UPLEFT: 
        begin 
          Dec(nX); 
          Dec(nY); 
        end; 
    end; // case 
    if not TMirMap(m_pMap).CanMove(nX, nY) then 
    begin 
      Result := False; 
      Exit; 
    end; 
  end; // for 
  Result := RunXY(nX, nY, nDir); 
end; 
 
function TCharObject.WalkXY(nX, nY, nDir: Integer): Boolean; 
var 
  nFlag: Integer; 
begin 
  nFlag := TMirMap(m_pMap).CheckDoorEvent(nX, nY, m_nEvent); 
 
  if nFlag > 0 then 
  begin 
    if nFlag = _DOOR_OPEN then 
    begin 
      AddRefMsg(RM_DOOROPEN, 1, m_nEvent, 0, 0, ''); 
    end; 
  end; 
 
  if TMirMap(m_pMap).CanMove(nX, nY) then 
  begin 
    if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nX, nY, self) then 
    begin 
 
      m_nCurrX := nX; 
      m_nCurrY := nY; 
      m_nDirection := nDir; 
      AddRefMsg(RM_WALK, nDir, m_nCurrX, m_nCurrY, 0, ''); 
      m_dwHealthTick := m_dwHealthTick - 20; 
 
      Result := True; 
      Exit; 
    end; 
  end; 
 
  Result := False; 
end; 
 
function TCharObject.RunXY(nX, nY, nDir: Integer): Boolean; 
begin 
  Result := False; 
  if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nX, nY, self) then 
  begin 
    AddRefMsg(RM_RUN, nDir, m_nCurrX, m_nCurrY, 0, ''); 
 
    m_nCurrX := nX; 
    m_nCurrY := nY; 
    m_nDirection := nDir; 
 
    m_dwHealthTick := m_dwHealthTick - 150; 
    m_dwSpellTick := m_dwSpellTick - 10; 
    m_dwSpellTick := max(0, m_dwSpellTick); 
    Dec(m_btPerHealth); 
    Dec(m_btPerSpell); 
 
    Result := True; 
  end; 
 
end; 
 
procedure TCharObject.IncHealthSpell(nHP, nMP: Integer); 
begin 
  if nHP >= 0 then 
  begin 
    if (m_WAbility.HP + nHP) < m_WAbility.MaxHP then 
    begin 
      m_WAbility.HP := m_WAbility.HP + nHP; 
    end 
    else 
    begin 
      m_WAbility.HP := m_WAbility.MaxHP; 
    end; 
  end; 
 
  if nMP >= 0 then 
  begin 
    if (m_WAbility.MP + nMP) < m_WAbility.MaxMP then 
    begin 
      m_WAbility.MP := m_WAbility.MP + nMP; 
    end 
    else 
    begin 
      m_WAbility.MP := m_WAbility.MaxMP; 
    end; 
  end; 
 
  HealthSpellChanged; 
end; 
 
//val : (+) dec spell 
//      (-) inc spell 
 
procedure TCharObject.DamageSpell(nVal: Integer); 
begin 
  if nVal > 0 then 
  begin 
    if (m_WAbility.MP - nVal) > 0 then 
    begin 
      m_WAbility.MP := m_WAbility.MP - nVal; 
    end 
    else 
    begin 
      m_WAbility.MP := 0; 
    end; 
  end 
  else 
  begin 
    if m_WAbility.MP - nVal < m_WAbility.MaxMP then 
    begin 
      m_WAbility.MP := m_WAbility.MP - nVal; 
    end 
    else 
    begin 
      m_WAbility.MP := m_WAbility.MaxMP; 
    end; 
  end; 
end; 
 
//nDamage : if (+) damage health 
//     if (-) healing health 
 
procedure TCharObject.DamageHealth(nDamage: Integer);      //掉血 
begin 
  if nDamage > 0 then 
  begin 
    if (m_WAbility.HP - nDamage) > 0 then 
    begin 
      m_WAbility.HP := m_WAbility.HP - nDamage; 
    end 
    else 
    begin 
      m_WAbility.HP := 0; 
    end; 
  end 
  else 
  begin 
    if (m_WAbility.HP - nDamage) < m_WAbility.MaxHP then 
    begin 
      m_WAbility.HP := m_WAbility.HP - nDamage; 
    end 
    else 
    begin 
      m_WAbility.HP := m_WAbility.MaxHP; 
    end; 
  end; 
end; 
 
function TCharObject.GetMagStruckDamage(nDamage: Integer): Integer; 
var 
  nArmor: Integer; 
begin 
  nArmor := 0; 
 
  if (HIBYTE(m_WAbility.MAC) - LOBYTE(m_WAbility.MAC) + 1) > 0 then 
  begin 
    nArmor := LOBYTE(m_WAbility.MAC) + (Random(32767) mod (HIBYTE(m_WAbility.MAC) 
      - LOBYTE(m_WAbility.MAC) + 1)); 
  end 
  else 
  begin 
    nArmor := LOBYTE(m_WAbility.MAC); 
  end; 
 
  nDamage := max(0, nDamage - nArmor); 
 
  if nDamage > 0 then 
  begin 
    if m_fAbilMagBubbleDefence then // 林贱狼阜 
    begin 
      nDamage := Round(nDamage / 100 * (m_btMagBubbleDefenceLevel + 2) * 8); 
      DamageBubbleDefence(); 
    end; 
  end; 
 
  Result := nDamage; 
end; 
 
procedure TCharObject.StruckDamage(nDamage: Integer); 
var 
  I: Integer; 
  fReCalc: Boolean; 
  nDura, nOldDura, 
    wDam: Integer; 
  pDress, 
    PUSERITEM: PUSERITEM_RCD; 
begin 
  if nDamage > 0 then 
  begin 
    fReCalc := False; 
    {  wDam    := (random(32767) mod 10) + 5; 
 
      if m_wStatusArr[POISON_DAMAGEARMOR] > 0 then 
      begin 
        wDam    := Round(wDam * 1.2); 
        nDamage := Round(nDamage * 1.2); 
      end; 
 
      if m_pUserInfo <> nil then 
      begin 
     //   pDress := TUserInfo(m_pUserInfo).GetDress; 
 
        if pDress <> nil then 
        begin 
          nDura   := pDress^.nDura; 
          nOldDura:= Round(nDura / 1000); 
          nDura   := nDura - wDam; 
 
          if nDura <= 0 then   // 粹酒 绝绢咙 
          begin 
            nDura := 0; 
            pDress^.nDura := nDura; 
 
            TUserInfo(m_pUserInfo).SetEmptyDress; 
 
            AddProcess(Self, RM_DURACHANGE, U_DRESS, nDura, pDress^.nDuraMax, 0, ''); 
            AddProcess(Self, RM_FEATURECHANGED, 0, GetFeatureToLong(), 0, 0, ''); 
 
            fReCalc := True; 
          end 
          else 
          begin 
            pDress^.nDura := nDura; 
          end; 
 
          if nOldDura <> Round(nDura / 1000) then 
          begin 
            AddProcess(self, RM_DURACHANGE, U_DRESS, pDress^.nDura, pDress^.nDuraMax, 0, ''); 
          end; 
        end; 
 
        for I := 0 to 7 do    // Iterate 
        begin 
          pUserItem  := TUserInfo(m_pUserInfo).GetUserItem(I); 
          if (pUserItem <> nil) and ((random(32767) mod 8) = 0) then 
          begin 
            nDura     := pUserItem^.nDura; 
            nOldDura  := Round(nDura / 1000); 
 
            nDura     := nDura - wDam; 
            if nDura <= 0 then 
            begin 
              nDura := 0; 
              pUserItem^.nDura := nDura; 
              TUserInfo(m_pUserInfo).SetEmptyUseItem(I); 
 
              AddProcess(self, RM_DURACHANGE, I, nDura, pUserItem^.nDuraMax, 0, ''); 
              AddProcess(self, RM_FEATURECHANGED, 0, GetFeatureToLong, 0, 0, ''); 
 
              fReCalc := True; 
            end 
            else 
            begin 
              pUserItem^.nDura := nDura; 
            end; 
 
            if nOldDura <> Round(nDura / 1000) then 
            begin 
              AddProcess(self, RM_DURACHANGE, I, pUserItem^.nDura, pUserItem^.nDuraMax, 0, ''); 
            end; 
          end; 
        end;    // for 
 
      end; 
     } 
    if fReCalc and (m_pUserInfo <> nil) then 
    begin 
      TPlayerObject(self).RecalcAbilitys; 
    end; 
    DamageHealth(nDamage); 
  end; 
end; 
 
function TCharObject.GetHitStruckDamage(nDamage: Integer): Integer; 
var 
  nArmor, nRnd: Integer; 
begin 
  nRnd := HIBYTE(m_WAbility.AC) - LOBYTE(m_WAbility.AC) + 1; 
 
  if nRnd > 0 then 
  begin 
    nArmor := LOBYTE(m_WAbility.AC) + (Random(32767) mod nRnd); 
  end 
  else 
  begin 
    nArmor := LOBYTE(m_WAbility.AC); 
  end; 
 
  nDamage := max(0, nDamage - nArmor); 
 
  if nDamage > 0 then 
  begin 
    if m_fAbilMagBubbleDefence then // 林贱狼阜 
    begin 
      nDamage := Round(nDamage / 100 * (m_btMagBubbleDefenceLevel + 2) * 8); 
      DamageBubbleDefence; 
    end; 
  end; 
 
  Result := nDamage; 
end; 
 
function TCharObject.GetAttackPower(nDamage, nVal: Integer): Integer; 
var 
  nPower: Integer; 
begin 
  nPower := 0; 
 
  if nVal < 0 then 
    nVal := 0; 
 
  nPower := nDamage + (Random(32767) mod (nVal + 1)); 
 
  Result := nPower; 
end; 
 
procedure TCharObject.DoDamageWeapon(nDamage: Integer); 
var 
  nDura, nOldDura: Integer; 
  pWeapon: PUSERITEM_RCD; 
begin 
  if m_pUserInfo <> nil then 
  begin 
    //   pWeapon := TUserInfo(m_pUserInfo).GetWeapon; 
 
    if pWeapon <> nil then 
    begin 
      nDura := pWeapon^.nDura; 
      nOldDura := Round(nDura / 1000); 
 
      nDura := nDura - nDamage; 
 
      if nDura <= 0 then // 粹酒 绝绢咙 
      begin 
        nDura := 0; 
        pWeapon^.nDura := nDura; 
        TPlayerObject(self).RecalcAbilitys; 
 
        TUserInfo(m_pUserInfo).SetEmptyWeapon; 
 
        AddProcess(self, RM_DURACHANGE, U_WEAPON, nDura, pWeapon^.nDuraMax, 0, 
          ''); 
      end 
      else 
      begin 
        pWeapon^.nDura := nDura; 
 
        if nOldDura <> Round(nDura / 1000) then 
        begin 
          AddProcess(self, RM_DURACHANGE, U_WEAPON, pWeapon^.nDura, 
            pWeapon^.nDuraMax, 0, ''); 
        end; 
      end; 
    end; 
  end; 
end; 
 
function TCharObject._Attack(wHitMode: Word; pCharObject: TCharObject): Boolean; 
var 
  nPower, 
    nSecPwr, 
    isok, 
    nWeaponDamage: Integer; 
begin 
  nPower := GetAttackPower(LOBYTE(m_WAbility.DC), (HIBYTE(m_WAbility.DC) - 
    LOBYTE(m_WAbility.DC))); 
  nSecPwr := 0; 
  AddRefMsg(RM_HIT, m_nDirection, m_nCurrX, m_nCurrY, 0, ''); 
  if pCharObject <> nil then 
  begin 
    if (wHitMode = CM_POWERHIT) and TUserInfo(m_pUserInfo).m_fPowerHitSkill then 
    begin 
      TUserInfo(m_pUserInfo).m_fPowerHitSkill := False; 
      nPower := nPower + m_btHitPlus; 
    end; 
 
    if (wHitMode = CM_FIREHIT) and TUserInfo(m_pUserInfo).m_fFireHitSkill then 
    begin 
      TUserInfo(m_pUserInfo).m_fFireHitSkill := False; 
      nPower := nPower + Round(nPower / 100 * (m_nHitDouble * 10)); 
    end; 
  end 
  else 
  begin 
    if (wHitMode = CM_POWERHIT) and TUserInfo(m_pUserInfo).m_fPowerHitSkill then 
    begin 
      TUserInfo(m_pUserInfo).m_fPowerHitSkill := False; 
      nPower := nPower + m_btHitPlus; 
    end; 
  end; 
 
  if wHitMode = CM_LONGHIT then 
  begin 
    nSecPwr := 0; 
 
    if TUserInfo(m_pUserInfo).m_lpTMagicErgumSkill <> nil then 
    begin 
      nSecPwr := Round(nPower / (3 + 2) * 
        (Integer(TUserInfo(m_pUserInfo).m_lpTMagicErgumSkill^.btLevel) + 2)); 
    end 
    else 
    begin 
      nSecPwr := nPower; 
    end; 
 
    if nSecPwr > 0 then 
    begin 
      SwordLongAttack(nSecPwr); 
    end; 
  end; 
 
  if wHitMode = CM_WIDEHIT then 
  begin 
    nSecPwr := 0; 
 
    if TUserInfo(m_pUserInfo).m_lpTMagicBanwolSkill <> nil then 
    begin 
      nSecPwr := Round(nPower / (3 + 10) * 
        (Integer(TUserInfo(m_pUserInfo).m_lpTMagicBanwolSkill^.btLevel) + 2)); 
    end 
    else 
    begin 
      nSecPwr := nPower; 
    end; 
 
    if nSecPwr > 0 then 
    begin 
      SwordWideAttack(nSecPwr); 
    end; 
  end; 
 
  if pCharObject <> nil then 
  begin 
    if IsProperTarget(pCharObject) then 
    begin 
      if m_btHitPoint < (Random(32767) mod pCharObject.m_btSpeedPoint) then 
      begin 
        nPower := 0; 
      end; 
 
    end 
    else 
    begin 
      nPower := 0; 
    end; 
  end; 
 
  if nPower > 0 then 
  begin 
 
    nPower := pCharObject.GetHitStruckDamage(nPower); 
    nWeaponDamage := (Random(32767) mod 5) + 2 - m_AddAbility.WeaponStrong; 
 
    { if nWeaponDamage > 0 then 
     begin 
       if TUserInfo(m_pUserInfo).GetWeapon <> nil then 
       begin 
         DoDamageWeapon(nWeaponDamage); 
       end; 
     end; 
    } 
    if nPower > 0 then 
    begin 
      pCharObject.StruckDamage(nPower); 
 
      AddDelayProcess(pCharObject, RM_STRUCK, nPower, pCharObject.m_WAbility.HP, 
        pCharObject.m_WAbility.MaxHP, Integer(self), '', 1550); 
 
       if (pCharObject.m_wObjectType <> _OBJECT_HUMAN) then 
       begin 
         pCharObject.AddProcess(pCharObject, RM_STRUCK, nPower, pCharObject.m_WAbility.HP, pCharObject.m_WAbility.MaxHP, Integer(Self), ''); 
       end; 
 
       Result := True; 
      Exit; 
    end; 
  end; 
 
  Result := False; 
end; 
 
function TCharObject.HitXY(wIdent: Word; nX, nY, nDir, nHitStyle: Integer): 
  Boolean; 
var 
  nLevel, nSpellPoint: Integer; 
  pCharObject: TCharObject; 
begin 
  if (GetTickCount - m_dwLatestHitTime) < 600 then 
  begin 
    Inc(m_nHitTimeOverCount); 
  end 
  else 
  begin 
    m_nHitTimeOverCount := 0; 
  end; 
 
  if m_nHitTimeOverCount < 2 then 
  begin 
    if (m_nCurrX = nX) and (m_nCurrY = nY) then 
    begin 
      if (wIdent = CM_WIDEHIT) and (TUserInfo(m_pUserInfo).m_lpTMagicBanwolSkill 
        <> nil) then 
      begin 
        if m_WAbility.MP > 0 then 
        begin 
          nLevel := 
            Integer(TUserInfo(m_pUserInfo).GetMagicRcdByID(_SKILL_BANWOL)^.btLevel); 
          nSpellPoint := GetMagicInfo(_SKILL_BANWOL).GetSpellPoint(nLevel); 
          DamageSpell(nSpellPoint); 
          HealthSpellChanged; 
        end 
        else 
        begin 
          wIdent := CM_HIT; 
        end; 
      end; 
 
      m_nDirection := nDir; 
      m_dwLatestHitTime := GetTickCount; 
 
      pCharObject := GetFrontObject; 
 
      if pCharObject <> nil then 
      begin 
        if _Attack(wIdent, pCharObject) then 
        begin 
          SelectTarget(pCharObject); 
 
          m_dwHealthTick := m_dwHealthTick - 100; 
          m_dwSpellTick := m_dwSpellTick - 100; 
          m_dwSpellTick := max(0, m_dwSpellTick); 
          m_btPerHealth := m_btPerHealth - 2; 
          m_btPerSpell := m_btPerSpell - 2; 
        end; 
      end; 
 
      if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
      begin 
        case wIdent of 
          CM_HIT: 
            begin 
              AddRefMsg(RM_HIT, nDir, m_nCurrX, m_nCurrY, nHitStyle, ''); 
            end; 
          CM_WIDEHIT: 
            begin 
              AddRefMsg(RM_WIDEHIT, nDir, m_nCurrX, m_nCurrY, nHitStyle, ''); 
            end; 
          CM_LONGHIT: 
            begin 
              AddRefMsg(RM_LONGHIT, nDir, m_nCurrX, m_nCurrY, nHitStyle, ''); 
            end; 
          CM_FIREHIT: 
            begin 
              AddRefMsg(RM_FIREHIT, nDir, m_nCurrX, m_nCurrY, nHitStyle, ''); 
            end; 
          CM_POWERHIT: 
            begin 
              AddRefMsg(RM_POWERHIT, nDir, m_nCurrX, m_nCurrY, nHitStyle, ''); 
            end; 
        end; 
      end; 
 
      {  if TUserInfo(m_pUserInfo).m_lpTMagicPowerHitSkill <> nil then // 抗档 八过 
        begin 
          dec(TUserInfo(m_pUserInfo).m_btAttackSkillCount); 
 
          if TUserInfo(m_pUserInfo).m_btAttackSkillCount = TUserInfo(m_pUserInfo).m_btAttackSkillPointCount then 
          begin 
            TUserInfo(m_pUserInfo).m_fPowerHitSkill := True; 
            SendSocket(nil, '+PWR'); 
          end; 
 
          if TUserInfo(m_pUserInfo).m_btAttackSkillCount <= 0 then 
          begin 
            TUserInfo(m_pUserInfo).m_btAttackSkillCount     := Byte(7 - Integer(TUserInfo(m_pUserInfo).m_lpTMagicPowerHitSkill^.btLevel)); 
            TUserInfo(m_pUserInfo).m_btAttackSkillPointCount:= random(32767) mod TUserInfo(m_pUserInfo).m_btAttackSkillCount; 
          end; 
        end; 
        } 
      Result := True; 
      Exit; 
    end; 
  end; 
 
  Result := False; 
end; 
 
procedure TCharObject.DoPushed(nDirection: Integer); 
var 
  nFrontX, nFrontY: Integer; 
begin 
  m_nDirection := nDirection; 
 
  GetFrontPosition(nFrontX, nFrontY); 
 
  if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nFrontX, nFrontY, 
    self) then 
  begin 
    AddRefMsg(RM_PUSH, GetBack(nDirection), m_nCurrX, m_nCurrY, 0, ''); 
 
    m_nCurrX := nFrontX; 
    m_nCurrY := nFrontY; 
  end; 
end; 
 
procedure TCharObject.GoldChanged; 
begin 
  if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
  begin 
    UpdateProcess(self, RM_GOLDCHANGED, 0, 0, 0, 0, ''); 
  end; 
end; 
 
procedure TCharObject.HealthSpellChanged; 
begin 
  if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
  begin 
    UpdateProcess(self, RM_HEALTHSPELLCHANGED, 0, 0, 0, 0, ''); 
  end; 
 
  if m_fOpenHealth then 
  begin 
    AddRefMsg(RM_HEALTHSPELLCHANGED, 0, 0, 0, 0, ''); 
  end; 
end; 
 
function TCharObject.AddCreatureSysop(nX, nY: Integer; pMonRaceInfo: 
  PMONRACEINFO_RCD; fSearch: Boolean): TCharObject; 
var 
  pMonObject: TMonsterObject; 
  p: pMONSTERGENINFO_RCD; 
  i: integer; 
begin 
  pMonObject := AddCreature(TMirMap(m_pMap), nX, nY, pMonRaceInfo.nIndex, 
    fSearch); 
 
  if pMonObject <> nil then 
  begin 
    if g_pMonGenInfo <> nil then 
    begin 
      for i := 0 to g_nNumOfMonGenInfo - 1 do 
      begin 
        if g_pMonGenInfo[i].szMonName = pMonObject.m_szName then 
        begin 
          g_pMonGenInfo[i].xMonsterObjList.Add(pMonObject); 
          //Inc(MonCount); 
          Break; 
        end; 
      end; 
    end; 
  end; 
 
  Result := TCharObject(pMonObject); 
end; 
 
procedure TCharObject.DoMotaebo; 
var 
  I: Integer; 
  nFrontX, nFrontY: Integer; 
  pCharObject: TCharObject; 
begin 
  pCharObject := GetFrontObject; 
 
  if pCharObject <> nil then 
  begin 
    for I := 0 to 4 do 
    begin 
      pCharObject.DoPushed(m_nDirection); 
 
      GetFrontPosition(nFrontX, nFrontY); 
 
      if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nFrontX, 
        nFrontY, self) then 
      begin 
        AddRefMsg(RM_RUSH, m_nDirection, m_nCurrX, m_nCurrY, 0, ''); 
 
        m_nCurrX := nFrontX; 
        m_nCurrY := nFrontY; 
 
        pCharObject := GetFrontObject; 
        if pCharObject = nil then 
        begin 
          Break; 
        end; 
      end 
      else 
      begin 
        Break; 
      end; 
    end; // for 
  end 
  else 
  begin 
    for I := 0 to 4 do 
    begin 
      GetFrontPosition(nFrontX, nFrontY); 
 
      if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nFrontX, 
        nFrontY, self) then 
      begin 
        AddRefMsg(RM_RUSH, m_nDirection, m_nCurrX, m_nCurrY, 0, ''); 
 
        m_nCurrX := nFrontX; 
        m_nCurrY := nFrontY; 
      end 
      else 
      begin 
        Break; 
      end; 
    end; 
  end; 
end; 
 
function TCharObject.DoShowHP(pCharObject: TCharObject; pMagicInfo: TObject; 
  nLevel: Integer): Boolean; 
begin 
  if pCharObject <> nil then 
  begin 
    if not pCharObject.m_fOpenHealth then 
    begin 
      if (Random(32767) mod 6) <= (3 + m_Ability.Level) then 
      begin 
        pCharObject.m_dwOpenHealthStart := GetTickCount; 
        pCharObject.m_dwOpenHealthTime := TMagicInfo(pMagicInfo).GetPower13(30 + 
          GetRPow(m_WAbility.SC) * 2, nLevel) * 1000; 
 
        pCharObject.AddDelayProcess(pCharObject, RM_DOOPENHEALTH, 0, 0, 0, 0, 
          '', 3000); 
 
        Result := True; 
        Exit; 
      end; 
    end; 
  end; 
 
  Result := False; 
end; 
 
procedure TCharObject.MakeOpenHealth; 
begin 
  m_fOpenHealth := True; 
 
  m_nCharStatusEx := m_nCharStatusEx or STATE_OPENHEATH; 
  m_nCharStatus := GetCharStatus; 
 
  AddRefMsg(RM_OPENHEALTH, 0, m_WAbility.HP, m_WAbility.MaxHP, 0, ''); 
end; 
 
procedure TCharObject.BreakOpenHealth; 
begin 
  m_fOpenHealth := False; 
 
  m_nCharStatusEx := m_nCharStatusEx xor STATE_OPENHEATH; 
  m_nCharStatus := GetCharStatus; 
 
  AddRefMsg(RM_CLOSEHEALTH, 0, 0, 0, 0, ''); 
end; 
 
function TCharObject.CharPushed(nDir, nPushCount: Integer): Integer; 
var 
  I: Integer; 
  nFrontX, nFrontY, nResult: Integer; 
begin 
  nResult := 0; 
 
  for I := 0 to nPushCount - 1 do 
  begin 
    GetFrontPosition(nFrontX, nFrontY); 
 
    if TMirMap(m_pMap).CanMove(nFrontX, nFrontY, False) then 
    begin 
      if TMirMap(m_pMap).MoveToMovingObject(m_nCurrX, m_nCurrY, nFrontX, 
        nFrontY, self) then 
      begin 
        m_nCurrX := nFrontX; 
        m_nCurrY := nFrontY; 
 
        AddRefMsg(RM_PUSH, GetBack(nDir), m_nCurrX, m_nCurrY, 0, ''); 
 
        Inc(nResult); 
      end; 
    end; 
  end; 
 
  m_nDirection := GetBack(nDir); 
 
  Result := nResult; 
end; 
 
function TCharObject.MagPushArround(nPushLevel: Integer): Integer; 
var 
  I: Integer; 
  nLevelGap, nPush, nDir: Integer; 
  nResult: Integer; 
  pVisibleObject: TVisibleObject; 
begin 
  nResult := 0; 
 
  with m_xVisibleObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pVisibleObject := items[I]; 
      if pVisibleObject <> nil then 
      begin 
        if (abs(m_nCurrX - pVisibleObject.pCharObject.m_nCurrX) <= 1) and 
          (abs(m_nCurrY - pVisibleObject.pCharObject.m_nCurrY) <= 1) then 
        begin 
          if (pVisibleObject.pCharObject.m_fIsDead = False) and 
            (pVisibleObject.pCharObject <> self) then 
          begin 
            if m_Ability.Level > pVisibleObject.pCharObject.m_Ability.Level then 
            begin 
              nLevelGap := m_Ability.Level - 
                pVisibleObject.pCharObject.m_Ability.Level; 
 
              if (Random(32767) mod 20) < (6 + nPushLevel * 3 + nLevelGap) then 
              begin 
                if IsProperTarget(pVisibleObject.pCharObject) then 
                begin 
                  nPush := 1 + max(0, nPushLevel - 1) + Random(32767) mod 2; 
                  nDir := GetNextDirection(pVisibleObject.pCharObject.m_nCurrX, 
                    pVisibleObject.pCharObject.m_nCurrY); 
                  pVisibleObject.pCharObject.CharPushed(nDir, nPush); 
                  Inc(nResult); 
                end; 
              end; 
            end; 
          end; 
        end; 
      end; 
    end; // for 
  end; // with 
 
  Result := nResult; 
end; 
 
function TCharObject.MagPassThroughMagic(nStartX, nStartY, nTargetX, nTargetY, 
  nDir, nPwr: Integer; fUndeadAttack: Boolean): Integer; 
var 
  I: Integer; 
  nResult: Integer; 
  pCharObject: TCharObject; 
begin 
  nResult := 0; 
  for I := 0 to 12 do 
  begin 
    pCharObject := TCharObject(TMirMap(m_pMap).GetObject(nStartX, nStartY)); 
 
    if pCharObject <> nil then 
    begin 
      if IsProperTarget(pCharObject) then 
      begin 
        if pCharObject.m_btAntiMagic <= (Random(32767) mod 10) then 
        begin 
          if fUndeadAttack then 
          begin 
            nPwr := Round(nPwr * 1.5); 
          end; 
 
          pCharObject.AddDelayProcess(self, RM_MAGSTRUCK, 0, nPwr, 0, 0, '', 
            600); 
 
          Inc(nResult); 
        end; 
      end; 
    end; 
 
    if not ((abs(nStartX - nTargetX) <= 0) and (abs(nStartY - nTargetY) <= 0)) 
      then 
    begin 
      nDir := GetNextDirection(nStartX, nStartY, nTargetX, nTargetY); 
 
      if not GetNextPosition(nStartX, nStartY, nDir, 1, nStartX, nStartY) then 
      begin 
        Break; 
      end; 
    end 
    else 
    begin 
      Break; 
    end; 
  end; 
 
  Result := nResult; 
end; 
 
function TCharObject.MagBubbleDefenceUp(nLevel, nSec: Integer): Boolean; 
var 
  nOldStatus: Cardinal; 
begin 
  if m_wStatusArr[STATE_BUBBLEDEFENCEUP] = 0 then 
  begin 
    nOldStatus := m_nCharStatus; 
 
    m_wStatusArr[STATE_BUBBLEDEFENCEUP] := Word(nSec); 
    m_dwStatusTime[STATE_BUBBLEDEFENCEUP] := GetTickCount; 
 
    m_nCharStatus := GetCharStatus; 
 
    if nOldStatus <> m_nCharStatus then 
      AddRefMsg(RM_CHARSTATUSCHANGED, m_sHitSpeed, m_nCharStatus, 0, 0, ''); 
 
    m_fAbilMagBubbleDefence := True; 
    m_btMagBubbleDefenceLevel := nLevel; 
 
    Result := True; 
    Exit; 
  end; 
 
  Result := False; 
end; 
 
procedure TCharObject.DamageBubbleDefence; 
begin 
  if m_wStatusArr[STATE_BUBBLEDEFENCEUP] > 0 then 
  begin 
    if m_wStatusArr[STATE_BUBBLEDEFENCEUP] > 3 then 
    begin 
      m_wStatusArr[STATE_BUBBLEDEFENCEUP] := m_wStatusArr[STATE_BUBBLEDEFENCEUP] 
        - 3; 
    end 
    else 
    begin 
      m_wStatusArr[STATE_BUBBLEDEFENCEUP] := 1; 
    end; 
  end; 
end; 
 
function TCharObject.MagMakeFireCross(nDamage, nHTime, nX, nY: Integer): 
  Integer; 
var 
  pEvent: TEvent; 
begin 
  if TEvent(TMirMap(m_pMap).GetEvent(nX, nY - 1)) <> nil then 
  begin 
    pEvent := TEvent(TFireBurnEvent.Create(nX, nY - 1, nHTime * 100, 
      TObject(self), nDamage)); 
    g_xEventList.Add(pEvent); 
  end; 
 
  if TEvent(TMirMap(m_pMap).GetEvent(nX - 1, nY)) <> nil then 
  begin 
    pEvent := TEvent(TFireBurnEvent.Create(nX - 1, nY, nHTime * 100, 
      TObject(self), nDamage)); 
    g_xEventList.Add(pEvent); 
  end; 
 
  if TEvent(TMirMap(m_pMap).GetEvent(nX, nY)) <> nil then 
  begin 
    pEvent := TEvent(TFireBurnEvent.Create(nX, nY, nHTime * 100, TObject(self), 
      nDamage)); 
    g_xEventList.Add(pEvent); 
  end; 
 
  if TEvent(TMirMap(m_pMap).GetEvent(nX + 1, nY)) <> nil then 
  begin 
    pEvent := TEvent(TFireBurnEvent.Create(nX + 1, nY, nHTime * 100, 
      TObject(self), nDamage)); 
    g_xEventList.Add(pEvent); 
  end; 
 
  if TEvent(TMirMap(m_pMap).GetEvent(nX, nY + 1)) <> nil then 
  begin 
    pEvent := TEvent(TFireBurnEvent.Create(nX, nY + 1, nHTime * 100, 
      TObject(self), nDamage)); 
    g_xEventList.Add(pEvent); 
  end; 
 
  Result := 1; 
end; 
 
function TCharObject.MagMakeHolyCurtain(nHTime, nX, nY: Integer): Integer; 
var 
  I, j: Integer; 
  nResult: Integer; 
  ObjectList: TThreadList; 
  pEvent: TEvent; 
  pHolySeizeInfo: THolySeizeInfo; 
  pTargetObject: TMonsterObject; 
begin 
  nResult := 0; 
  ObjectList := TThreadList.Create; 
  pHolySeizeInfo := nil; 
 
  if TMirMap(m_pMap).CanMove(nX, nY, True) then 
  begin 
    ObjectList := TThreadList.Create; 
    TMirMap(m_pMap).GetMapObject(nX, nY, 1, 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_wObjectType and _OBJECT_ANIMAL) > 0) and 
            (pTargetObject.m_Ability.Level < (m_Ability.Level - 1 + Random(32767) 
            mod 4)) 
            and (pTargetObject.m_Ability.Level < 50) and 
              (pTargetObject.m_pMasterObject = nil) then 
          begin 
            pTargetObject.MakeHolySeize(nHTime * 1000); 
 
            if pHolySeizeInfo = nil then 
            begin 
              pHolySeizeInfo := THolySeizeInfo.Create; 
              for j := 0 to 6 do // Iterate 
              begin 
                pHolySeizeInfo.Event[0] := nil; 
                pHolySeizeInfo.dwOpenTime := GetTickCount; 
                pHolySeizeInfo.dwSeizeTime := nHTime * 1000; 
              end; // for 
 
              pHolySeizeInfo.SeizeList.Add(pTargetObject); 
              Inc(nResult); 
            end; 
          end; 
        end; 
        Delete(I); 
      end; // for 
    end; // with 
    ObjectList.UnlockList; 
 
    if (nResult > 0) and (pHolySeizeInfo <> nil) then 
    begin 
      pEvent := TEvent(THolyCurtainEvent.Create(nX - 1, nY - 2, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[0] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX + 1, nY - 2, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[1] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX - 2, nY - 1, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[2] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX + 2, nY - 1, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[3] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX - 2, nY + 1, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[4] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX + 2, nY + 1, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[5] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX - 1, nY + 2, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[6] := pEvent; 
 
      pEvent := TEvent(THolyCurtainEvent.Create(nX + 1, nY + 2, nHTime * 1000, 
        self)); 
      g_xEventList.Add(pEvent); 
      pHolySeizeInfo.Event[7] := pEvent; 
 
      g_xHolySeizeList.Add(pHolySeizeInfo); 
    end; 
  end; 
  Result := nResult; 
end; 
 
function TCharObject.DirectAttack(pCharObject: TCharObject; nDamage: Integer): 
  Boolean; 
begin 
  if (pCharObject.m_wObjectType and _OBJECT_HUMAN) > 0 then 
  begin 
    Result := False; 
    Exit; 
  end; 
 
  if IsProperTarget(pCharObject) then 
  begin 
    if (Random(32767) mod pCharObject.m_btSpeedPoint) < m_btHitPoint then 
    begin 
      pCharObject.StruckDamage(nDamage); 
      pCharObject.AddDelayProcess(pCharObject, RM_STRUCK, nDamage, 
        pCharObject.m_WAbility.HP, pCharObject.m_WAbility.MaxHP, Integer(self), 
        '', 550); 
 
      Result := True; 
      Exit; 
    end; 
  end; 
 
  Result := False; 
end; 
 
function TCharObject.SwordLongAttack(nDamage: Integer): Boolean; 
var 
  nX, nY: Integer; 
  pTargetObject: TCharObject; 
begin 
  nX := 0; 
  nY := 0; 
 
  if GetNextPosition(m_nDirection, 2, nX, nY) then 
  begin 
    pTargetObject := TCharObject(TMirMap(m_pMap).GetObject(nX, nY)); 
 
    if (pTargetObject <> nil) and (nDamage > 0) then 
    begin 
      if IsProperTarget(pTargetObject) then 
      begin 
        DirectAttack(pTargetObject, nDamage); 
        SelectTarget(pTargetObject); 
 
        Result := True; 
        Exit; 
      end; 
    end; 
  end; 
  Result := False; 
end; 
 
function TCharObject.SwordWideAttack(nDamage: Integer): Boolean; 
const 
  WideSearchPos: array[0..7] of Integer = (6, 7, 0, 1, 2, 3, 4, 5); 
  WideAttack: array[0..2] of Integer = (6, 7, 1); 
var 
  I: Integer; 
  nDir, 
    nX, nY: Integer; 
  pTargetObject: TCharObject; 
begin 
  for I := 0 to 2 do // Iterate 
  begin 
    nDir := (m_nDirection + WideAttack[I]) mod 8; 
 
    if GetNextPosition(nDir, 1, nX, nY) then 
    begin 
      pTargetObject := TCharObject(TMirMap(m_pMap).GetObject(nX, nY)); 
 
      if (pTargetObject <> nil) and (nDamage > 0) then 
      begin 
        if IsProperTarget(pTargetObject) then 
        begin 
          DirectAttack(pTargetObject, nDamage); 
          SelectTarget(pTargetObject); 
 
          Result := True; 
          Exit; 
        end; 
      end; 
    end; 
  end; // for 
  Result := False; 
end; 
 
function TCharObject.MagElecBlizzard(nPower: Integer): Boolean; 
var 
  I: Integer; 
  fFlag: Boolean; 
  ObjectList: TThreadList; 
  pCharObject: TCharObject; 
begin 
  fFlag := False; 
 
  ObjectList := TThreadList.Create; 
  TMirMap(m_pMap).GetMapObject(m_nCurrX, m_nCurrY, 2, ObjectList); 
 
  with ObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pCharObject := items[I]; 
      if (pCharObject.m_wObjectType and _OBJECT_ANIMAL) > 0 then 
      begin 
        if TMonsterObject(pCharObject).m_btLifeAttrib > 0 then 
        begin 
          pCharObject.AddProcess(self, RM_MAGSTRUCK, 0, nPower, 0, 0, ''); 
        end 
        else 
        begin 
          pCharObject.AddProcess(self, RM_MAGSTRUCK, 0, nPower div 10, 0, 0, 
            ''); 
        end; 
 
        fFlag := True; 
      end; 
      Delete(I); 
    end; // for 
  end; // with 
  ObjectList.UnlockList; 
  Result := fFlag; 
end; 
 
function TCharObject.MagBigExplosion(nPower, nX, nY, nWide: Integer): Boolean; 
var 
  I: Integer; 
  fFlag: Boolean; 
  ObjectList: TThreadList; 
  pCharObject: TCharObject; 
begin 
  ObjectList := TThreadList.Create; 
  TMirMap(m_pMap).GetMapObject(nX, nY, nWide, ObjectList); 
 
  with ObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do 
    begin 
      pCharObject := items[I]; 
      if IsProperTarget(pCharObject) then 
      begin 
        SelectTarget(pCharObject); 
        pCharObject.AddProcess(self, RM_MAGSTRUCK, 0, nPower, 0, 0, ''); 
        fFlag := True; 
      end; 
      Delete(I); 
    end; // for 
  end; // with 
  ObjectList.UnlockList; 
  Result := fFlag; 
end; 
 
function TCharObject.MagBigHealing(nPower, nX, nY: Integer): Boolean; 
var 
  I: Integer; 
  fFlag: Boolean; 
  ObjectList: TThreadList; 
  pCharObject: TCharObject; 
begin 
  fFlag := False; 
  ObjectList := TThreadList.Create; 
  TMirMap(m_pMap).GetMapObject(nX, nY, 1, ObjectList); 
 
  with ObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do 
    begin 
      pCharObject := items[I]; 
      if IsProperFriend(pCharObject) then 
      begin 
        if pCharObject.m_WAbility.HP < pCharObject.m_WAbility.MaxHP then 
        begin 
          pCharObject.AddDelayProcess(self, RM_MAGHEALING, 0, nPower, 0, 0, '', 
            800); 
          fFlag := True; 
        end; 
      end; 
      Delete(I); 
    end; // for 
  end; // with 
  ObjectList.UnlockList; 
  Result := fFlag; 
end; 
 
function TCharObject.MagDefenceUp(nState, nSec: Integer): Boolean; 
var 
  fFlag: Boolean; 
  szMsg: string; 
begin 
  fFlag := False; 
 
  if m_wStatusArr[nState] > 0 then 
  begin 
    if nSec > m_wStatusArr[nState] then 
    begin 
      m_wStatusArr[nState] := nSec; 
      fFlag := True; 
    end; 
  end 
  else 
  begin 
    m_wStatusArr[nState] := nSec; 
    fFlag := True; 
  end; 
 
  m_dwStatusTime[nState] := GetTickCount; 
 
  if nState = STATE_DEFENCEUP then 
  begin 
    szMsg := IDS_DEFENCEUP; 
  end 
  else 
  begin 
    szMsg := IDS_MAGDEFENCEUP; 
  end; 
 
  SysMsg(szMsg, 1); 
 
  if (m_wObjectType and _OBJECT_HUMAN) > 0 then 
  begin 
    TPlayerObject(self).RecalcAbilitys; 
  end; 
 
  AddProcess(self, RM_ABILITY, 0, 0, 0, 0, ''); 
  Result := False; 
end; 
 
function TCharObject.MagMakeDefenceArea(nX, nY, nRange, nSec, nState: Integer): 
  Boolean; 
var 
  I, X, Y: Integer; 
  nStartX, nEndX, 
    nStartY, nEndY: Integer; 
  nCount: Integer; 
  pMapCellInfo: PMAPCELLINFO_RCD; 
  pOSObject: POSOBJECT_RCD; 
  pCharObject: TCharObject; 
begin 
  nStartX := nX - nRange; 
  nEndX := nX + nRange; 
  nStartY := nY - nRange; 
  nEndY := nY + nRange; 
  nCount := 0; 
 
  for X := nStartX to nEndX do // Iterate 
  begin 
    for Y := nStartY to nEndY do // Iterate 
    begin 
      pMapCellInfo := TMirMap(m_pMap).GetMapCellInfo(X, Y); 
      if pMapCellInfo^.m_xpObjectList <> nil then 
      begin 
        with pMapCellInfo^.m_xpObjectList.LockList do 
        begin 
          for I := 0 to COunt - 1 do // Iterate 
          begin 
            pOSObject := items[I]; 
            if pOSObject^.btType = OS_MOVINGOBJECT then 
            begin 
              pCharObject := TCharObject(pOSObject^.pObject); 
              if not pCharObject.m_fIsGhost then 
              begin 
                if IsProperFriend(pCharObject) then 
                begin 
                  pCharObject.MagDefenceUp(nState, nSec); 
                  Inc(nCount); 
                end; 
              end; 
            end; 
          end; // for 
        end; // with 
        pMapCellInfo^.m_xpObjectList.UnlockList; 
      end; 
    end; // for 
  end; // for 
  if nCount > 0 then 
  begin 
    Result := True; 
  end 
  else 
  begin 
    Result := False; 
  end; 
end; 
 
function TCharObject.MagMakePrivateTransparent(nHTime: Integer): Boolean; 
var 
  I: Integer; 
  ObjectList: TThreadList; 
  pCharObject: TCharObject; 
begin 
  if m_wStatusArr[STATE_TRANSPARENT] > 0 then 
  begin 
    Result := False; 
    Exit; 
  end; 
 
  ObjectList := TThreadList.Create; 
  TMirMap(m_pMap).GetMapObject(m_nCurrX, m_nCurrY, 9, ObjectList); 
 
  with ObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pCharObject := items[I]; 
      if (pCharObject.m_wObjectType and _OBJECT_ANIMAL) > 0 then 
      begin 
        if pCharObject.m_pTargetObject = self then 
        begin 
          if (abs(pCharObject.m_nCurrX - m_nCurrX) > 1) or 
            (abs(pCharObject.m_nCurrY - m_nCurrY) > 1) then 
          begin 
            pCharObject.m_pTargetObject := nil; 
          end; 
        end; 
      end; 
      Delete(I); 
    end; // for 
  end; // with 
  ObjectList.UnlockList; 
 
  m_wStatusArr[STATE_TRANSPARENT] := nHTime; 
 
  m_nCharStatus := GetCharStatus; 
  AddRefMsg(RM_CHARSTATUSCHANGED, m_sHitSpeed, m_nCharStatus, 0, 0, ''); 
 
  m_fHumHideMode := True; 
  m_fFixedHideMode := True; 
 
  Result := False; 
end; 
 
function TCharObject.MagMakeGroupTransparent(nX, nY, nHTime: Integer): Boolean; 
var 
  I: Integer; 
  fFlag: Boolean; 
  ObjectList: TThreadList; 
  pCharObject: TCharObject; 
begin 
  fFlag := False; 
 
  ObjectList := TThreadList.Create; 
  TMirMap(m_pMap).GetMapObject(nX, nY, 1, ObjectList); 
 
  with ObjectList.LockList do 
  begin 
    for I := COunt - 1 downto 0 do // Iterate 
    begin 
      pCharObject := items[I]; 
      if IsProperFriend(pCharObject) then 
      begin 
        if pCharObject.m_wStatusArr[STATE_TRANSPARENT] = 0 then 
        begin 
          AddDelayProcess(pCharObject, RM_TRANSPARENT, 0, nHTime, 0, 0, '', 
            800); 
          fFlag := True; 
        end; 
      end; 
      Delete(I); 
    end; // for 
  end; // with 
  ObjectList.UnlockList; 
 
  Result := fFlag; 
end; 
 
function TCharObject.MagTurnUndead(pCharObject: TCharObject; nX, nY, nLevel: 
  Integer): Boolean; 
var 
  nlvGap: Integer; 
  pMonsterObject: TMonsterObject; 
begin 
  pMonsterObject := TMonsterObject(pCharObject); 
 
  if pMonsterObject.m_btLifeAttrib = LA_UNDEAD then 
  begin 
    pMonsterObject.Struck(self); 
 
    SelectTarget(pMonsterObject); 
 
    if (pMonsterObject.m_Ability.Level < m_Ability.Level - 1 + (Random(32767) mod 
      4)) and (pMonsterObject.m_Ability.Level < 50) then 
    begin 
      nlvGap := m_Ability.Level - pMonsterObject.m_Ability.Level; 
 
      if (Random(32767) mod 100) < (15 + nLevel * 7 + nlvGap) then 
      begin 
        pMonsterObject.SetLastHiter(self); 
        pMonsterObject.m_WAbility.HP := 0; 
        Result := True; 
        Exit; 
      end; 
    end; 
  end; 
 
  Result := False; 
end; 
 
procedure TCharObject.SendSocket(lpDefMsg: PDEFAULTMESSAGE_RCD; pszPacket: 
  string); 
var 
  dwBytesSends: LongWord; 
  MsgHdr: TMSGHEADER_RCD; 
  lpSendBuff: array[0..19820] of Char; 
  nLen, 
    nLength: Integer; 
begin 
  dwBytesSends := 0; 
  MsgHdr.nCode := $AA55AA55; 
  MsgHdr.wIdent := GM_Data; 
  MsgHdr.wUserGateIndex := TUserInfo(m_pUserInfo).m_nUserGateIndex; 
  MsgHdr.wUserListIndex := TUserInfo(m_pUserInfo).m_nUserServerIndex; 
  MsgHdr.nSocket := TUserInfo(m_pUserInfo).m_Socket; 
 
  if lpDefMsg <> nil then 
  begin 
    if pszPacket <> '' then 
    begin 
      nLength := Length(pszPacket) + 1; 
 
      if nLength >= 8096 then 
      begin 
        //        InsertLogMsg('SendSocket:Packet is too long'); 
        Exit; 
      end; 
 
      MsgHdr.nLength := 12 + nLength; 
      nLen := 20 + MsgHdr.nLength; 
 
      CopyMemory(@lpSendBuff[0], @MsgHdr, 20); 
      CopyMemory(@lpSendBuff[20], lpDefMsg, 12); 
      CopyMemory(@lpSendBuff[32], @pszPacket[1], MsgHdr.nLength - 12); 
 
    end 
    else 
    begin 
      MsgHdr.nLength := 12; 
      nLen := 20 + MsgHdr.nLength; 
 
      CopyMemory(@lpSendBuff[0], @MsgHdr, 20); 
      CopyMemory(@lpSendBuff[20], lpDefMsg, 12); 
 
 
    end; 
  end 
  else 
  begin 
    nLen := Length(pszPacket); 
    MsgHdr.nLength := -nLen; 
 
    nLen := 20 + nLen + 1; 
 
 
    CopyMemory(@lpSendBuff[0], @MsgHdr, 20); 
    CopyMemory(@lpSendBuff[20], @(pszPacket[1]), nLen); 
 
 
  end; 
  TUserInfo(m_pUserInfo).m_pGateInfo.Socket.SendBuf(lpSendBuff, nLen); 
    //,lpSendBuff^.nLen); 
 
end; 
 
procedure TCharObject.GetQueryUserName(pCharObject: TCharObject; nX, nY: 
  Integer); 
var 
  nPos: Integer; 
  szEncodeMsg: string[32]; 
  szCharName: string; 
  DefMsg: TDEFAULTMESSAGE_RCD; 
begin 
  pCharObject.GetCharName(szCharName); 
 
  DefMsg := MakeDefaultMsg(SM_USERNAME, Integer(pCharObject), 
    pCharObject.GetThisCharColor, 0, 0); 
  szEncodeMsg := EncodeString(szCharName); 
 
  SendSocket(@DefMsg, szEncodeMsg); 
end; 
 
procedure TCharObject.SysMsg(pszMsg: string; nMode: Integer); 
begin 
  if nMode = 1 then 
  begin 
    AddProcess(self, RM_SYSMESSAGE2, 0, 0, 0, 0, pszMsg); 
  end 
  else 
  begin 
    AddProcess(self, RM_SYSMESSAGE, 0, 0, 0, 0, pszMsg); 
  end; 
end; 
 
function TCharObject.GetFeatureToLong: Integer; 
begin 
  Result := m_tFeature.Feature; 
end; 
 
function TCharObject.GetRPow(wPower: Word): Byte; 
begin 
  if HIBYTE(wPower) > LOBYTE(wPower) then 
  begin 
    Result := LOBYTE(wPower) + Random(32767) mod (HIBYTE(wPower) - LOBYTE(wPower) 
      + 1); 
  end 
  else 
  begin 
    Result := LOBYTE(wPower); 
  end; 
end; 
 
end.