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.