X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_monsters.pas;h=a437ff9bdcd13e7c1ea72bc56b75efe61c4a72cb;hb=bab60f8ad58f03e8a35dbb44aba77bb9ff9201f9;hp=59b5506a5ee732d02bde51f54f49820dedc7a1c2;hpb=829537fc7b2b29baaab7287e54fba2cdd8d00b5c;p=d2df-sdl.git diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index 59b5506..a437ff9 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -14,13 +14,15 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} +{$M+} +{.$DEFINE D2F_DEBUG_MONS_MOVE} unit g_monsters; interface uses - g_basic, e_graphics, g_phys, g_textures, - g_saveload, BinEditor, g_panel; + g_basic, e_graphics, g_phys, g_textures, g_grid, + g_saveload, BinEditor, g_panel, xprofiler; const MONSTATE_SLEEP = 0; @@ -79,9 +81,8 @@ type FFirePainTime: Integer; FFireAttacker: Word; vilefire: TAnimation; - - treeNode: Integer; // node in dyntree or -1 - arrIdx: Integer; // in gMonsters + mProxyId: Integer; // node in dyntree or -1 + mArrIdx: Integer; // in gMonsters FDieTriggers: Array of Integer; FSpawnTrigger: Integer; @@ -90,9 +91,13 @@ type function findNewPrey(): Boolean; procedure ActivateTriggers(); + procedure setGameX (v: Integer); inline; + procedure setGameY (v: Integer); inline; + public FNoRespawn: Boolean; FFireTime: Integer; + trapCheckFrameId: DWord; // for `g_weapons.CheckTrap()` constructor Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1); destructor Destroy(); override; @@ -133,6 +138,17 @@ type procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! + procedure setPosition (ax, ay: Integer; callPosChanged: Boolean=true); inline; + + procedure getMapBox (out x, y, w, h: Integer); inline; + + public + property Obj: TObj read FObj; + + property proxyId: Integer read mProxyId; + property arrIdx: Integer read mArrIdx; + + published property MonsterType: Byte read FMonsterType; property MonsterHealth: Integer read FHealth write FHealth; property MonsterAmmo: Integer read FAmmo write FAmmo; @@ -145,12 +161,11 @@ type property MonsterPain: Integer read FPain write FPain; property MonsterAnim: Byte read FCurAnim write FCurAnim; - property Obj: TObj read FObj; property UID: Word read FUID write FUID; property SpawnTrigger: Integer read FSpawnTrigger write FSpawnTrigger; - property GameX: Integer read FObj.X write FObj.X; - property GameY: Integer read FObj.Y write FObj.Y; + property GameX: Integer read FObj.X write setGameX; + property GameY: Integer read FObj.Y write setGameY; property GameVelX: Integer read FObj.Vel.X write FObj.Vel.X; property GameVelY: Integer read FObj.Vel.Y write FObj.Vel.Y; property GameAccelX: Integer read FObj.Accel.X write FObj.Accel.X; @@ -160,28 +175,30 @@ type property StartID: Integer read FStartID; end; -procedure g_Monsters_LoadData(); -procedure g_Monsters_FreeData(); -procedure g_Monsters_Init(); -procedure g_Monsters_Free(); -function g_Monsters_Create(MonsterType: Byte; X, Y: Integer; - Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; -procedure g_Monsters_Update(); -procedure g_Monsters_Draw(); -procedure g_Monsters_DrawHealth(); -function g_Monsters_Get(UID: Word): TMonster; -procedure g_Monsters_killedp(); -procedure g_Monsters_SaveState(var Mem: TBinMemoryWriter); -procedure g_Monsters_LoadState(var Mem: TBinMemoryReader); -function g_Monsters_GetIDByName(name: String): Integer; -function g_Monsters_GetNameByID(MonsterType: Byte): String; -function g_Monsters_GetKilledBy(MonsterType: Byte): String; +// will be called from map loader +procedure g_Mons_InitTree (x, y, w, h: Integer); -type - TEachMonsterCB = function (monidx: Integer; mon: TMonster): Boolean is nested; // return `true` to stop +procedure g_Monsters_LoadData (); +procedure g_Monsters_FreeData (); +procedure g_Monsters_Init (); +procedure g_Monsters_Free (clearGrid: Boolean=true); +function g_Monsters_Create (MonsterType: Byte; X, Y: Integer; Direction: TDirection; + AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; +procedure g_Monsters_Update (); +procedure g_Monsters_Draw (); +procedure g_Monsters_DrawHealth (); +function g_Monsters_ByUID (UID: Word): TMonster; +procedure g_Monsters_killedp (); +procedure g_Monsters_SaveState (var Mem: TBinMemoryWriter); +procedure g_Monsters_LoadState (var Mem: TBinMemoryReader); +function g_Monsters_GetIDByName (name: String): Integer; +function g_Monsters_GetNameByID (MonsterType: Byte): String; +function g_Monsters_GetKilledBy (MonsterType: Byte): String; -function g_Mons_ForEach (cb: TEachMonsterCB): Boolean; + +type + TEachMonsterCB = function (mon: TMonster): Boolean is nested; // return `true` to stop // throws on invalid uid function g_Mons_ByIdx (uid: Integer): TMonster; inline; @@ -189,80 +206,155 @@ function g_Mons_ByIdx (uid: Integer): TMonster; inline; // can return null function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline; +function g_Mons_TotalCount (): Integer; inline; + function g_Mons_IsAnyAliveAt (x, y: Integer; width, height: Integer): Boolean; +function g_Mons_ForEach (cb: TEachMonsterCB): Boolean; +function g_Mons_ForEachAlive (cb: TEachMonsterCB): Boolean; + function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean; -function g_Mons_ForEachAtAlive (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean; +function g_Mons_ForEachAliveAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean; + +function g_Mons_getNewTrapFrameId (): DWord; + + +type + TMonsAlongLineCB = function (mon: TMonster; tag: Integer): Boolean is nested; + +function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster; var gmon_debug_use_sqaccel: Boolean = true; +//HACK! +procedure g_Mons_ProfilersBegin (); +procedure g_Mons_ProfilersEnd (); + +procedure g_Mons_LOS_Start (); inline; +procedure g_Mons_LOS_End (); inline; + +var + profMonsLOS: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY! + + +type + TMonsterGrid = specialize TBodyGridBase; + +var + monsGrid: TMonsterGrid = nil; // DO NOT USE! public for debugging only! + + +var + gmon_debug_think: Boolean = true; + gmon_debug_one_think_step: Boolean = false; + + implementation uses e_log, g_main, g_sound, g_gfx, g_player, g_game, g_weapons, g_triggers, MAPDEF, g_items, g_options, g_console, g_map, Math, SysUtils, g_menu, wadreader, - g_language, g_netmsg, z_aabbtree; + g_language, g_netmsg, idpool; -// ////////////////////////////////////////////////////////////////////////// // -type - TDynAABBTreeMonsBase = specialize TDynAABBTreeBase; - TDynAABBTreeMons = class(TDynAABBTreeMonsBase) - function getFleshAABB (out aabb: AABB2D; flesh: TMonster; tag: Integer): Boolean; override; +// ////////////////////////////////////////////////////////////////////////// // +procedure g_Mons_ProfilersBegin (); +begin + if (profMonsLOS = nil) then profMonsLOS := TProfiler.Create('LOS CALC', g_profile_history_size); + profMonsLOS.mainBegin(g_profile_los); + if g_profile_los then + begin + profMonsLOS.sectionBegin('loscalc'); + profMonsLOS.sectionEnd(); end; +end; -function TDynAABBTreeMons.getFleshAABB (out aabb: AABB2D; flesh: TMonster; tag: Integer): Boolean; +procedure g_Mons_ProfilersEnd (); begin - result := false; - if (flesh = nil) then raise Exception.Create('DynTree: trying to get dimensions of inexistant monsters'); - if (flesh.Obj.Rect.Width < 1) or (flesh.Obj.Rect.Height < 1) then raise Exception.Create('DynTree: monster without size, wtf?!'); - aabb := AABB2D.CreateWH(flesh.Obj.X+flesh.Obj.Rect.X, flesh.Obj.Y+flesh.Obj.Rect.Y, flesh.Obj.Rect.Width, flesh.Obj.Rect.Height); - if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!'); - result := true; + if (profMonsLOS <> nil) and (g_profile_los) then profMapCollision.mainEnd(); +end; + +procedure g_Mons_LOS_Start (); inline; +begin + profMonsLOS.sectionBeginAccum('loscalc'); +end; + +procedure g_Mons_LOS_End (); inline; +begin + profMonsLOS.sectionEnd(); end; +// ////////////////////////////////////////////////////////////////////////// // var - monsTree: TDynAABBTreeMons = nil; + monCheckTrapLastFrameId: DWord; + + +procedure TMonster.getMapBox (out x, y, w, h: Integer); inline; +begin + x := FObj.X+FObj.Rect.X; + y := FObj.Y+FObj.Rect.Y; + w := FObj.Rect.Width; + h := FObj.Rect.Height; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster; +begin + if not assigned(cb) then begin result := nil; exit; end; + result := monsGrid.forEachAlongLine(x0, y0, x1, y1, cb, -1, log); +end; //WARNING! call this after monster position was changed, or coldet will not work right! procedure TMonster.positionChanged (); var - x, y: Integer; + x, y, w, h: Integer; + nx, ny, nw, nh: Integer; begin - {$IF DEFINED(D2F_DEBUG)} - //e_WriteLog(Format('monster #%d(%u): pos=(%d,%d); rpos=(%d,%d)', [arrIdx, UID, FObj.X, FObj.Y, FObj.Rect.X, FObj.Rect.Y]), MSG_NOTIFY); + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + //e_WriteLog(Format('monster #%d(%u): pos=(%d,%d); rpos=(%d,%d)', [mArrIdx, UID, FObj.X, FObj.Y, FObj.Rect.X, FObj.Rect.Y]), MSG_NOTIFY); {$ENDIF} - if (treeNode = -1) then + if (mProxyId = -1) then begin - treeNode := monsTree.insertObject(self, 0); - {$IF DEFINED(D2F_DEBUG)} - monsTree.getNodeXY(treeNode, x, y); - e_WriteLog(Format('monster #%d(%u): inserted into the tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY); + mProxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height); + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + monsGrid.getBodyXY(mProxyId, x, y); + e_WriteLog(Format('monster #%d:(%u): inserted into the grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); {$ENDIF} end else begin - monsTree.getNodeXY(treeNode, x, y); - if (FObj.X+FObj.Rect.X = x) and (FObj.Y+FObj.Rect.Y = y) then exit; // nothing to do - {$IF DEFINED(D2F_DEBUG)}e_WriteLog(Format('monster #%d(%u): updating tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY);{$ENDIF} - - {$IFDEF TRUE} - monsTree.updateObject(treeNode); - {$ELSE} - monsTree.removeObject(treeNode); - treeNode := monsTree.insertObject(self); - {$ENDIF} + monsGrid.getBodyDims(mProxyId, x, y, w, h); + getMapBox(nx, ny, nw, nh); - {$IF DEFINED(D2F_DEBUG)} - monsTree.getNodeXY(treeNode, x, y); - e_WriteLog(Format('monster #%d(%u): updated tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY); + if (w <> nw) or (h <> nh) then + begin + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + e_WriteLog(Format('monster #%d:(%u): resized; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + monsGrid.moveResizeBody(mProxyId, nx, ny, nw, nh); + end + else if (x <> nx) or (y <> ny) then + begin + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + e_WriteLog(Format('monster #%d:(%u): updating grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + monsGrid.moveBody(mProxyId, nx, ny); + end + else + begin + exit; // nothing to do + end; + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + monsGrid.getBodyXY(mProxyId, x, y); + e_WriteLog(Format('monster #%d:(%u): updated grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); {$ENDIF} end; end; @@ -278,19 +370,6 @@ const ANIM_ATTACK2 = 5; ANIM_PAIN = 6; - STATE_SLEEP = 0; - STATE_GO = 1; - STATE_RUN = 2; - STATE_CLIMB = 3; - STATE_DIE = 4; - STATE_DEAD = 5; - STATE_ATTACK = 6; - STATE_SHOOT = 7; - STATE_PAIN = 8; - STATE_WAIT = 9; - STATE_REVIVE = 10; - STATE_RUNOUT = 11; - MONSTER_SIGNATURE = $534E4F4D; // 'MONS' // Òàáëèöà òèïîâ àíèìàöèè ìîíñòðîâ: @@ -383,8 +462,8 @@ const LeftAnim: Boolean; wX, wY: Integer; // Îòêóäà âûëåòèò ïóëÿ AnimSpeed: Array [ANIM_SLEEP..ANIM_PAIN] of Byte; - AnimDeltaRight: Array [ANIM_SLEEP..ANIM_PAIN] of TPoint; - AnimDeltaLeft: Array [ANIM_SLEEP..ANIM_PAIN] of TPoint; + AnimDeltaRight: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; + AnimDeltaLeft: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; end = // SLEEP GO DIE MESS ATTACK ATTACK2 PAIN ((LeftAnim: False; wX: 54; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //DEMON AnimDeltaRight: ((X: 1; Y: 4), (X: 1; Y: 4), (X: 0; Y: 4), (X: 0; Y: 4), (X: 2; Y: 6), (X: 2; Y: 6), (X: 2; Y: 5)); @@ -472,38 +551,55 @@ const var gMonsters: array of TMonster; + uidMap: array [0..65535] of TMonster; // monster knows it's index + freeInds: TIdPool = nil; + +procedure clearUidMap (); var - pt_x: Integer = 0; - pt_xs: Integer = 1; - pt_y: Integer = 0; - pt_ys: Integer = 1; - soulcount: Integer = 0; + idx: Integer; +begin + for idx := 0 to High(uidMap) do uidMap[idx] := nil; + freeInds.clear(); +end; -function allocMonster(): DWORD; +function g_Mons_getNewTrapFrameId (): DWord; var - i, olen: Integer; + f: Integer; begin - for i := 0 to High(gMonsters) do + Inc(monCheckTrapLastFrameId); + if monCheckTrapLastFrameId = 0 then begin - if (gMonsters[i] = nil) then + // wraparound + monCheckTrapLastFrameId := 1; + for f := 0 to High(gMonsters) do begin - result := i; - exit; + if (gMonsters[f] <> nil) then gMonsters[f].trapCheckFrameId := 0; end; end; + result := monCheckTrapLastFrameId; +end; - olen := Length(gMonsters); - if (olen = 0) then - begin - SetLength(gMonsters, 64); - result := 0; - end - else + +var + pt_x: Integer = 0; + pt_xs: Integer = 1; + pt_y: Integer = 0; + pt_ys: Integer = 1; + soulcount: Integer = 0; + + +function allocMonster (): DWORD; +var + f, olen: Integer; +begin + result := freeInds.alloc(); + if (result > High(gMonsters)) then begin - result := olen; - SetLength(gMonsters, Length(gMonsters)+32); + olen := Length(gMonsters); + SetLength(gMonsters, result+64); + for f := olen to High(gMonsters) do gMonsters[f] := nil; end; end; @@ -535,6 +631,7 @@ begin Result := False; end; + function BehaviourDamage(SpawnerUID: Word; BH, SelfType: Byte): Boolean; var m: TMonster; @@ -546,7 +643,7 @@ begin UIDType := g_GetUIDType(SpawnerUID); if UIDType = UID_MONSTER then begin - m := g_Monsters_Get(SpawnerUID); + m := g_Monsters_ByUID(SpawnerUID); if m = nil then Exit; MonsterType := m.FMonsterType; end; @@ -564,6 +661,7 @@ begin end; end; + function canShoot(m: Byte): Boolean; begin Result := False; @@ -576,12 +674,14 @@ begin end; end; -function isCorpse(o: PObj; immediately: Boolean): Integer; + +function isCorpse (o: PObj; immediately: Boolean): Integer; function monsCollCheck (mon: TMonster; atag: Integer): Boolean; begin + atag := atag; // shut up, fpc! result := false; // don't stop - if (mon.FState = STATE_DEAD) and g_Obj_Collide(o, @mon.FObj) then + if (mon.FState = MONSTATE_DEAD) and g_Obj_Collide(o, @mon.FObj) then begin case mon.FMonsterType of // Íå âîñêðåñèòü: MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER, @@ -604,14 +704,14 @@ begin // Èùåì ìåðòâûõ ìîíñòðîâ ïîáëèçîñòè if gmon_debug_use_sqaccel then begin - mon := monsTree.aabbQuery(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height, monsCollCheck); - if (mon <> nil) then result := mon.arrIdx; + mon := monsGrid.forEachInAABB(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height, monsCollCheck); + if (mon <> nil) then result := mon.mArrIdx; end else begin for a := 0 to High(gMonsters) do begin - if (gMonsters[a] <> nil) and (gMonsters[a].FState = STATE_DEAD) and g_Obj_Collide(o, @gMonsters[a].FObj) then + if (gMonsters[a] <> nil) and (gMonsters[a].FState = MONSTATE_DEAD) and g_Obj_Collide(o, @gMonsters[a].FObj) then begin case gMonsters[a].FMonsterType of // Íå âîñêðåñèòü: MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER, @@ -865,7 +965,9 @@ begin g_Sound_CreateWADEx('SOUND_MONSTER_FISH_ATTACK', GameWAD+':MSOUNDS\FISH_ATTACK'); - monsTree := TDynAABBTreeMons.Create(); + freeInds := TIdPool.Create(); + clearUidMap(); + monCheckTrapLastFrameId := 0; end; procedure g_Monsters_FreeData(); @@ -1083,7 +1185,8 @@ begin g_Sound_Delete('SOUND_MONSTER_FISH_ATTACK'); - monsTree.Free(); + freeInds.Free(); + freeInds := nil; end; procedure g_Monsters_Init(); @@ -1091,18 +1194,33 @@ begin soulcount := 0; end; -procedure g_Monsters_Free(); +procedure g_Monsters_Free (clearGrid: Boolean=true); var a: Integer; begin - if gMonsters <> nil then - for a := 0 to High(gMonsters) do - gMonsters[a].Free(); - - monsTree.reset(); + e_LogWritefln('Cleared monster data (clearGrid=%s)', [clearGrid]); + if (clearGrid) then + begin + monsGrid.Free(); + monsGrid := nil; + end; + for a := 0 to High(gMonsters) do gMonsters[a].Free(); gMonsters := nil; + clearUidMap(); + monCheckTrapLastFrameId := 0; end; + +// will be called from map loader +procedure g_Mons_InitTree (x, y, w, h: Integer); +begin + monsGrid.Free(); + monsGrid := TMonsterGrid.Create(x, y, w, h); + //clearUidMap(); // why not? + e_LogWritefln('%s', ['Recreated monster tree']); +end; + + function g_Monsters_Create(MonsterType: Byte; X, Y: Integer; Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; var @@ -1125,8 +1243,10 @@ begin mon := TMonster.Create(MonsterType, find_id, ForcedUID); gMonsters[find_id] := mon; - mon.arrIdx := find_id; - mon.treeNode := -1; + mon.mArrIdx := find_id; + mon.mProxyId := -1; + + uidMap[mon.FUID] := mon; // Íàñòðàèâàåì ïîëîæåíèå with mon do @@ -1160,53 +1280,62 @@ begin if gMonsters = nil then Exit; -// Ïðèêîëèñò ñìååòñÿ íàä ñìåðòüþ èãðîêà: + // Ïðèêîëèñò ñìååòñÿ íàä ñìåðòüþ èãðîêà: h := High(gMonsters); for a := 0 to h do + begin if (gMonsters[a] <> nil) then + begin with gMonsters[a] do + begin if (FMonsterType = MONSTER_MAN) and - (FState <> STATE_DEAD) and - (FState <> STATE_SLEEP) and - (FState <> STATE_DIE) then + (FState <> MONSTATE_DEAD) and + (FState <> MONSTATE_SLEEP) and + (FState <> MONSTATE_DIE) then begin g_Sound_PlayExAt('SOUND_MONSTER_TRUP', FObj.X, FObj.Y); Exit; end; + end; + end; + end; end; procedure g_Monsters_Update(); var a: Integer; begin -// Öåëåóêàçàòåëü: + // Öåëåóêàçàòåëü if gTime mod (GAME_TICK*2) = 0 then begin pt_x := pt_x+pt_xs; pt_y := pt_y+pt_ys; - if Abs(pt_x) > 246 then - pt_xs := -pt_xs; - if Abs(pt_y) > 100 then - pt_ys := -pt_ys; + if abs(pt_x) > 246 then pt_xs := -pt_xs; + if abs(pt_y) > 100 then pt_ys := -pt_ys; end; gMon := True; // Äëÿ ðàáîòû BlockMon'à - if gMonsters <> nil then + if gmon_debug_think or gmon_debug_one_think_step then + begin + gmon_debug_one_think_step := false; for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) then - if not gMonsters[a].FRemoved then - begin - if g_Game_IsClient then - gMonsters[a].ClientUpdate() - else - gMonsters[a].Update(); - end + begin + if (gMonsters[a] = nil) then continue; + if not gMonsters[a].FRemoved then + begin + if g_Game_IsClient then + gMonsters[a].ClientUpdate() else - begin - gMonsters[a].Free(); - gMonsters[a] := nil; - end; + gMonsters[a].Update(); + end + else + begin + gMonsters[a].Free(); + gMonsters[a] := nil; + end; + end; + end; gMon := False; end; @@ -1216,9 +1345,12 @@ var a: Integer; begin if gMonsters <> nil then + begin for a := 0 to High(gMonsters) do - if gMonsters[a] <> nil then - gMonsters[a].Draw(); + begin + if (gMonsters[a] <> nil) then gMonsters[a].Draw(); + end; + end; end; procedure g_Monsters_DrawHealth(); @@ -1230,28 +1362,19 @@ begin e_TextureFontGetSize(gStdFont, fW, fH); for a := 0 to High(gMonsters) do + begin if gMonsters[a] <> nil then begin e_TextureFontPrint(gMonsters[a].FObj.X + gMonsters[a].FObj.Rect.X, gMonsters[a].FObj.Y + gMonsters[a].FObj.Rect.Y + gMonsters[a].FObj.Rect.Height - fH, IntToStr(gMonsters[a].FHealth), gStdFont); end; + end; end; -function g_Monsters_Get(UID: Word): TMonster; -var - a: Integer; +function g_Monsters_ByUID (UID: Word): TMonster; begin - Result := nil; - - if gMonsters <> nil then - for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and - (gMonsters[a].FUID = UID) then - begin - Result := gMonsters[a]; - Break; - end; + result := uidMap[UID]; end; procedure g_Monsters_SaveState(var Mem: TBinMemoryWriter); @@ -1261,11 +1384,16 @@ var begin // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ìîíñòðîâ: count := 0; - if gMonsters <> nil then + if (gMonsters <> nil) then + begin for i := 0 to High(gMonsters) do - if gMonsters[i] <> nil then - if gMonsters[i].FMonsterType <> MONSTER_NONE then - count := count + 1; + begin + if (gMonsters[i] <> nil) then + begin + if (gMonsters[i].FMonsterType <> MONSTER_NONE) then count += 1; + end; + end; + end; Mem := TBinMemoryWriter.Create((count+1) * 350); @@ -1283,15 +1411,19 @@ begin // Ñîõðàíÿåì ìîíñòðîâ: for i := 0 to High(gMonsters) do - if gMonsters[i] <> nil then - if gMonsters[i].FMonsterType <> MONSTER_NONE then + begin + if (gMonsters[i] <> nil) then + begin + if (gMonsters[i].FMonsterType <> MONSTER_NONE) then begin - // Òèï ìîíñòðà: + // Òèï ìîíñòðà: b := gMonsters[i].MonsterType; Mem.WriteByte(b); - // Ñîõðàíÿåì äàííûå ìîíñòðà: + // Ñîõðàíÿåì äàííûå ìîíñòðà: gMonsters[i].SaveState(Mem); end; + end; + end; end; procedure g_Monsters_LoadState(var Mem: TBinMemoryReader); @@ -1302,7 +1434,7 @@ var begin if Mem = nil then exit; - g_Monsters_Free(); + g_Monsters_Free(false); // Çàãðóæàåì èíôîðìàöèþ öåëåóêàçàòåëÿ Mem.ReadInt(pt_x); @@ -1365,6 +1497,11 @@ end; { T M o n s t e r : } +procedure TMonster.setGameX (v: Integer); inline; begin FObj.X := v; positionChanged(); end; +procedure TMonster.setGameY (v: Integer); inline; begin FObj.Y := v; positionChanged(); end; +procedure TMonster.setPosition (ax, ay: Integer; callPosChanged: Boolean=true); inline; begin FObj.X := ax; FObj.Y := ay; if callPosChanged then positionChanged(); end; + + procedure TMonster.ActionSound(); begin case FMonsterType of @@ -1553,8 +1690,8 @@ begin FObj.Accel.X := 0; FObj.Accel.Y := 0; FDirection := FStartDirection; - GameX := FStartX; - GameY := FStartY; + {GameX}FObj.X := FStartX; + {GameY}FObj.Y := FStartY; FObj.Rect := MONSTERTABLE[FMonsterType].Rect; FHealth := MONSTERTABLE[FMonsterType].Health; FAmmo := 0; @@ -1566,7 +1703,7 @@ begin FChainFire := False; FShellTimer := -1; - FState := STATE_SLEEP; + FState := MONSTATE_SLEEP; FCurAnim := ANIM_SLEEP; positionChanged(); // this updates spatial accelerators @@ -1581,7 +1718,7 @@ end; constructor TMonster.Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1); var a: Integer; - FramesID: DWORD; + FramesID: DWORD = 0; s: String; res: Boolean; begin @@ -1594,7 +1731,7 @@ begin g_Obj_Init(@FObj); - FState := STATE_SLEEP; + FState := MONSTATE_SLEEP; FCurAnim := ANIM_SLEEP; FHealth := MONSTERTABLE[MonsterType].Health; FMaxHealth := FHealth; @@ -1611,8 +1748,9 @@ begin FFirePainTime := 0; FFireAttacker := 0; - treeNode := -1; - arrIdx := -1; + mProxyId := -1; + mArrIdx := -1; + trapCheckFrameId := 0; if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then FBloodKind := BLOOD_SPARKS @@ -1709,7 +1847,7 @@ begin Result := False; // Óìèðàåò, óìåð èëè âîñêðåøàåòñÿ => óðîí äåëàòü íåêîìó: - if (FState = STATE_DEAD) or (FState = STATE_DIE) or (FState = STATE_REVIVE) then + if (FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE) or (FState = MONSTATE_REVIVE) then Exit; // Ðûáó â âîäå áüåò òîêîì => ïàíèêà áåç óðîíà: @@ -1721,7 +1859,7 @@ begin else FDirection := D_LEFT; Result := True; - SetState(STATE_RUN); + SetState(MONSTATE_RUN); Exit; end; @@ -1742,10 +1880,10 @@ begin FPain := FPain+aDamage; // Åñëè áîëü ñóùåñòâåííàÿ, òî ìåíÿåì ñîñòîÿíèå íà áîëåâîå: - if FState <> STATE_PAIN then + if FState <> MONSTATE_PAIN then if (FPain >= MONSTERTABLE[FMonsterType].MinPain) and (FMonsterType <> MONSTER_BARREL) then - SetState(STATE_PAIN); + SetState(MONSTATE_PAIN); // Åñëè ðàçðåøåíà êðîâü - ñîçäàåì áðûçãè êðîâè: if (gBloodCount > 0) then @@ -1763,8 +1901,7 @@ begin end; // Òåïåðü öåëü - óäàðèâøèé, åñëè òîëüêî íå ñàì ñåáÿ: - if (SpawnerUID <> FUID) and - (BehaviourDamage(SpawnerUID, FBehaviour, FMonsterType)) then + if (SpawnerUID <> FUID) and (BehaviourDamage(SpawnerUID, FBehaviour, FMonsterType)) then begin FTargetUID := SpawnerUID; FTargetTime := 0; @@ -1826,6 +1963,7 @@ begin begin FObj.Rect.Y := FObj.Rect.Y + FObj.Rect.Height-12; FObj.Rect.Height := 12; + positionChanged(); end; // Óðîí áûë ñèëüíûì => ñëàáûå - â êàøó: @@ -1835,12 +1973,12 @@ begin (FMonsterType = MONSTER_MAN)) then begin g_Sound_PlayExAt('SOUND_MONSTER_SLOP', FObj.X, FObj.Y); - SetState(STATE_DIE, ANIM_MESS); + SetState(MONSTATE_DIE, ANIM_MESS); end else begin DieSound(); - SetState(STATE_DIE); + SetState(MONSTATE_DIE); end; // Àêòèâèðîâàòü òðèããåðû, æäóùèå ñìåðòè ýòîãî ìîíñòðà: @@ -1849,10 +1987,10 @@ begin FHealth := 0; end else - if FState = STATE_SLEEP then + if FState = MONSTATE_SLEEP then begin // Ñïàë, ðàçáóäèëè íåñìåðòåëüíûì óäàðîì: FPain := MONSTERTABLE[FMonsterType].Pain; - SetState(STATE_GO); + SetState(MONSTATE_GO); end; if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterState(FUID); @@ -1870,8 +2008,7 @@ begin if FHealth < FMaxHealth then begin IncMax(FHealth, Value, FMaxHealth); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_MonsterState(FUID); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterState(FUID); Result := True; end; end; @@ -1888,14 +2025,27 @@ begin vilefire.Free(); - if (treeNode <> -1) then + if (mProxyId <> -1) then begin - {$IF DEFINED(D2F_DEBUG)} - e_WriteLog(Format('monster #%d(%u): removed from tree; nodeid=%d', [arrIdx, UID, treeNode]), MSG_NOTIFY); - {$ENDIF} - monsTree.removeObject(treeNode); + if (monsGrid <> nil) then + begin + monsGrid.removeBody(mProxyId); + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + e_WriteLog(Format('monster #%d:(%u): removed from grid; mProxyid=%d', [mArrIdx, UID, mProxyId]), MSG_NOTIFY); + {$ENDIF} + end; + mProxyId := -1; end; + if (mArrIdx <> -1) and (mArrIdx < Length(gMonsters)) then + begin + freeInds.release(mArrIdx); + gMonsters[mArrIdx] := nil; + end; + mArrIdx := -1; + + uidMap[FUID] := nil; + inherited Destroy(); end; @@ -1910,18 +2060,21 @@ begin // Åñëè êîëäóí ñòðåëÿåò, òî ðèñóåì îãîíü: if FMonsterType = MONSTER_VILE then - if FState = STATE_SHOOT then + if FState = MONSTATE_SHOOT then if GetPos(FTargetUID, @o) then vilefire.Draw(o.X+o.Rect.X+(o.Rect.Width div 2)-32, o.Y+o.Rect.Y+o.Rect.Height-128, M_NONE); // Íå â îáëàñòè ðèñîâàíèÿ íå ðåñóåì: - if not g_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, - sX-128, sY-128, sWidth+256, sHeight+256) then - Exit; + if (g_dbg_scale = 1.0) then + begin + if not g_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, + sX-128, sY-128, sWidth+256, sHeight+256) then + Exit; + end; // Ýòè ìîíñòðû, óìèðàÿ, íå îñòàâëÿþò òðóïîâ: - if FState = STATE_DEAD then + if FState = MONSTATE_DEAD then case FMonsterType of MONSTER_BARREL, MONSTER_SOUL, MONSTER_PAIN: Exit; end; @@ -2000,8 +2153,7 @@ procedure TMonster.Push(vx, vy: Integer); begin FObj.Accel.X := FObj.Accel.X + vx; FObj.Accel.Y := FObj.Accel.Y + vy; - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_MonsterPos(FUID); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterPos(FUID); end; procedure TMonster.SetState(State: Byte; ForceAnim: Byte = 255); @@ -2010,14 +2162,14 @@ var begin // Åñëè ñîñòîÿíèå = íà÷àëè óìèðàòü, à ýòîò ìîíñòð = Lost_Soul, // òî ñîáëþäàåì îãðàíè÷åíèå êîëè÷åñòâà Lost_Soul'îâ: - if (State = STATE_DIE) and (MonsterType = MONSTER_SOUL) then + if (State = MONSTATE_DIE) and (MonsterType = MONSTER_SOUL) then soulcount := soulcount-1; // Ïðèñìåðòè - íåëüçÿ ñðàçó íà÷èíàòü àòàêîâàòü èëè áåãàòü: case FState of - STATE_DIE, STATE_DEAD, STATE_REVIVE: - if (State <> STATE_DEAD) and (State <> STATE_REVIVE) and - (State <> STATE_GO) then + MONSTATE_DIE, MONSTATE_DEAD, MONSTATE_REVIVE: + if (State <> MONSTATE_DEAD) and (State <> MONSTATE_REVIVE) and + (State <> MONSTATE_GO) then Exit; end; @@ -2028,14 +2180,14 @@ begin // Íîâàÿ àíèìàöèÿ ïðè íîâîì ñîñòîÿíèè: case FState of - STATE_SLEEP: Anim := ANIM_SLEEP; - STATE_PAIN: Anim := ANIM_PAIN; - STATE_WAIT: Anim := ANIM_SLEEP; - STATE_CLIMB, STATE_RUN, STATE_RUNOUT, STATE_GO: Anim := ANIM_GO; - STATE_SHOOT: Anim := ANIM_ATTACK; - STATE_ATTACK: Anim := ANIM_ATTACK; - STATE_DIE: Anim := ANIM_DIE; - STATE_REVIVE: + MONSTATE_SLEEP: Anim := ANIM_SLEEP; + MONSTATE_PAIN: Anim := ANIM_PAIN; + MONSTATE_WAIT: Anim := ANIM_SLEEP; + MONSTATE_CLIMB, MONSTATE_RUN, MONSTATE_RUNOUT, MONSTATE_GO: Anim := ANIM_GO; + MONSTATE_SHOOT: Anim := ANIM_ATTACK; + MONSTATE_ATTACK: Anim := ANIM_ATTACK; + MONSTATE_DIE: Anim := ANIM_DIE; + MONSTATE_REVIVE: begin // íà÷àëè âîñðåøàòüñÿ Anim := FCurAnim; FAnim[Anim, FDirection].Revert(True); @@ -2125,8 +2277,7 @@ begin NET_GFX_TELE); end; - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_MonsterPos(FUID); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterPos(FUID); Result := True; end; @@ -2145,15 +2296,15 @@ begin // Ðûáû "ëåòàþò" òîëüêî â âîäå: if FMonsterType = MONSTER_FISH then if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then - if (FState <> STATE_DIE) and (FState <> STATE_DEAD) then + if (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) then fall := False; // Ëåòàþùèå ìîíòñðû: if ((FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_CACO)) and - (FState <> STATE_DIE) and - (FState <> STATE_DEAD) then + (FState <> MONSTATE_DIE) and + (FState <> MONSTATE_DEAD) then fall := False; // Ìåíÿåì ñêîðîñòü òîëüêî ïî ÷åòíûì êàäðàì: @@ -2191,7 +2342,7 @@ begin oldvelx := FObj.Vel.X; // Ñîïðîòèâëåíèå âîçäóõà äëÿ òðóïà: - if (FState = STATE_DIE) or (FState = STATE_DEAD) then + if (FState = MONSTATE_DIE) or (FState = MONSTATE_DEAD) then FObj.Vel.X := z_dec(FObj.Vel.X, 1); if FFireTime > 0 then @@ -2202,7 +2353,7 @@ begin begin OnFireFlame(1); FFireTime := FFireTime - 1; - if (FState <> STATE_DIE) and (FState <> STATE_DEAD) then + if (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) then if FFirePainTime = 0 then begin Damage(5, FFireAttacker, 0, 0, HIT_FLAME); @@ -2214,15 +2365,15 @@ begin end; // Ìåðòâûé íè÷åãî íå äåëàåò: - if (FState = STATE_DEAD) then + if (FState = MONSTATE_DEAD) then goto _end; // AI ìîíñòðîâ âûêëþ÷åí: if g_debug_MonsterOff then begin FSleep := 1; - if FState <> STATE_SLEEP then - SetState(STATE_SLEEP); + if FState <> MONSTATE_SLEEP then + SetState(MONSTATE_SLEEP); end; // Âîçìîæíî, ñîçäàåì ïóçûðüêè â âîäå: @@ -2248,7 +2399,7 @@ begin // Åñëè ïðîøåë ïåðâûé êàäð àíèìàöèè âçðûâà áî÷êè, òî âçðûâ: if FMonsterType = MONSTER_BARREL then begin - if (FState = STATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and + if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and (FAnim[FCurAnim, FDirection].Counter = 0) then g_Weapon_Explode(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), FObj.Y+FObj.Rect.Y+FObj.Rect.Height-16, @@ -2293,8 +2444,8 @@ begin // Ïðîáóåì óâåðíóòüñÿ îò ëåòÿùåé ïóëè: if fall then - if (FState in [STATE_GO, STATE_RUN, STATE_RUNOUT, - STATE_ATTACK, STATE_SHOOT]) then + if (FState in [MONSTATE_GO, MONSTATE_RUN, MONSTATE_RUNOUT, + MONSTATE_ATTACK, MONSTATE_SHOOT]) then if g_Weapon_Danger(FUID, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, 50) then if (g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj)) and @@ -2302,7 +2453,7 @@ begin FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; case FState of - STATE_PAIN: // Ñîñòîÿíèå - Áîëü + MONSTATE_PAIN: // Ñîñòîÿíèå - Áîëü begin // Áîëü ñèëüíàÿ => ìîíñòð êðè÷èò: if FPain >= MONSTERTABLE[FMonsterType].Pain then @@ -2321,11 +2472,11 @@ begin begin FPain := 0; FAmmo := -9; - SetState(STATE_GO); + SetState(MONSTATE_GO); end; end; - STATE_SLEEP: // Ñîñòîÿíèå - Ñîí + MONSTATE_SLEEP: // Ñîñòîÿíèå - Ñîí begin // Ñïèì: FSleep := FSleep + 1; @@ -2349,7 +2500,7 @@ begin FTargetUID := gPlayers[a].UID; FTargetTime := 0; WakeUpSound(); - SetState(STATE_GO); + SetState(MONSTATE_GO); Break; end; @@ -2378,30 +2529,30 @@ begin FTargetUID := gMonsters[a].UID; FTargetTime := 0; WakeUpSound(); - SetState(STATE_GO); + SetState(MONSTATE_GO); Break; end; end; end; - STATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå + MONSTATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå begin // Æäåì: FSleep := FSleep - 1; // Âûæäàëè äîñòàòî÷íî - èäåì: if FSleep < 0 then - SetState(STATE_GO); + SetState(MONSTATE_GO); end; - STATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) + MONSTATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) begin // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: if WordBool(st and MOVE_BLOCK) then begin Turn(); FSleep := 40; - SetState(STATE_RUNOUT); + SetState(MONSTATE_RUNOUT); goto _end; end; @@ -2411,7 +2562,7 @@ begin if isCorpse(@FObj, False) <> -1 then begin FObj.Vel.X := 0; - SetState(STATE_ATTACK, ANIM_ATTACK2); + SetState(MONSTATE_ATTACK, ANIM_ATTACK2); goto _end; end; @@ -2464,7 +2615,7 @@ begin if FMonsterType <> MONSTER_FISH then begin FSleep := 15; - SetState(STATE_RUN); + SetState(MONSTATE_RUN); if Random(2) = 0 then FDirection := D_LEFT else @@ -2480,7 +2631,7 @@ begin FObj.Rect.Height, FUID, ACTIVATE_MONSTERPRESS) <> nil then begin // Ñìîãëè íàæàòü êíîïêó - íåáîëüøîå îæèäàíèå FSleep := 4; - SetState(STATE_WAIT); + SetState(MONSTATE_WAIT); goto _end; end; @@ -2493,7 +2644,7 @@ begin begin // Ñòîèì íà òâåðäîì ïîëó èëè ñòóïåíè // Ïðûæîê ÷åðåç ñòåíó: FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; - SetState(STATE_CLIMB); + SetState(MONSTATE_CLIMB); end; end; @@ -2516,7 +2667,7 @@ begin end; // Ðûáå áîëüíî: - SetState(STATE_PAIN); + SetState(MONSTATE_PAIN); FPain := FPain + 50; end else // Ðûáà â âîäå @@ -2539,7 +2690,7 @@ begin else FDirection := D_RIGHT; FSleep := 20; - SetState(STATE_RUN); + SetState(MONSTATE_RUN); end; end; end @@ -2628,14 +2779,14 @@ begin FObj.Vel.X := 0; end; - STATE_RUN: // Ñîñòîÿíèå - Áåã + MONSTATE_RUN: // Ñîñòîÿíèå - Áåã begin // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: if WordBool(st and MOVE_BLOCK) then begin Turn(); FSleep := 40; - SetState(STATE_RUNOUT); + SetState(MONSTATE_RUNOUT); goto _end; end; @@ -2646,7 +2797,7 @@ begin if (FSleep <= 0) or (WordBool(st and MOVE_HITWALL) and ((FObj.Vel.Y+FObj.Accel.Y) = 0)) then begin FSleep := 0; - SetState(STATE_GO); + SetState(MONSTATE_GO); // Ñòåíà - èäåì îáðàòíî: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then Turn(); @@ -2669,7 +2820,7 @@ begin FObj.Vel.X := 0; end; - STATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî + MONSTATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî begin // Âûøëè èç ÁëîêÌîíà: if (not WordBool(st and MOVE_BLOCK)) and (FSleep > 0) then @@ -2681,7 +2832,7 @@ begin if FSleep <= -18 then begin FSleep := 0; - SetState(STATE_GO); + SetState(MONSTATE_GO); // Ñòåíà/ÁëîêÌîí - èäåì îáðàòíî: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then Turn(); @@ -2704,21 +2855,21 @@ begin FObj.Vel.X := 0; end; - STATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) + MONSTATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) begin // Äîñòèãëè âûñøåé òî÷êè ïðûæêà èëè ñòåíà êîí÷èëàñü => ïåðåõîäèì íà øàã: if ((FObj.Vel.Y+FObj.Accel.Y) >= 0) or (not WordBool(st and MOVE_HITWALL)) then begin FSleep := 0; - SetState(STATE_GO); + SetState(MONSTATE_GO); // Ñòåíà íå êîí÷èëàñü => áåæèì îò íåå: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then begin Turn(); FSleep := 15; - SetState(STATE_RUN); + SetState(MONSTATE_RUN); end; end; @@ -2736,14 +2887,14 @@ begin FObj.Vel.X := 0; end; - STATE_ATTACK, // Ñîñòîÿíèå - Àòàêà - STATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà + MONSTATE_ATTACK, // Ñîñòîÿíèå - Àòàêà + MONSTATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà begin // Lost_Soul âðåçàëñÿ â ñòåíó ïðè àòàêå => ïåðåõîäèò íà øàã: if FMonsterType = MONSTER_SOUL then begin if WordBool(st and (MOVE_HITWALL or MOVE_HITCEIL or MOVE_HITLAND)) then - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -2753,12 +2904,12 @@ begin FObj.Vel.X := z_dec(FObj.Vel.X, 1); // Íóæíî ñòðåëÿòü, à ìîíñòð - êîëäóí: - if (FMonsterType = MONSTER_VILE) and (FState = STATE_SHOOT) then + if (FMonsterType = MONSTER_VILE) and (FState = MONSTATE_SHOOT) then begin // Öåëü ïîãèáëà => èäåì äàëüøå: if not GetPos(FTargetUID, @o) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -2766,7 +2917,7 @@ begin // Öåëü íå âèäíî => èäåì äàëüøå: if not g_Look(@FObj, @o, FDirection) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -2774,7 +2925,7 @@ begin // Öåëü â âîäå - íå çàãîðèòñÿ => èäåì äàëüøå: if g_Obj_CollideWater(@o, 0, 0) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -2790,11 +2941,11 @@ begin _end: // Ñîñòîÿíèå - Âîñêðåøåíèå: - if FState = STATE_REVIVE then + if FState = MONSTATE_REVIVE then if FAnim[FCurAnim, FDirection].Played then begin // Îáðàòíàÿ àíèìàöèÿ óìèðàíèÿ çàêîí÷èëàñü - èäåì äàëüøå: FAnim[FCurAnim, FDirection].Revert(False); - SetState(STATE_GO); + SetState(MONSTATE_GO); end; // Åñëè åñòü àíèìàöèÿ îãíÿ êîëäóíà - ïóñòü îíà èäåò: @@ -2802,12 +2953,12 @@ _end: vilefire.Update(); // Ñîñòîÿíèå - Óìèðàåò è òåêóùàÿ àíèìàöèÿ ïðîèãðàíà: - if (FState = STATE_DIE) and + if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection] <> nil) and (FAnim[FCurAnim, FDirection].Played) then begin // Óìåð: - SetState(STATE_DEAD); + SetState(MONSTATE_DEAD); // Pain_Elemental ïðè ñìåðòè âûïóñêàåò 3 Lost_Soul'à: if (FMonsterType = MONSTER_PAIN) then @@ -2816,32 +2967,33 @@ _end: FObj.Y+FObj.Rect.Y+20, D_LEFT); if mon <> nil then begin - mon.SetState(STATE_GO); + mon.SetState(MONSTATE_GO); mon.FNoRespawn := True; Inc(gTotalMonsters); - if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); + if g_Game_IsNet then MH_SEND_MonsterSpawn(mon.UID); end; mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), FObj.Y+FObj.Rect.Y+20, D_RIGHT); if mon <> nil then begin - mon.SetState(STATE_GO); + mon.SetState(MONSTATE_GO); mon.FNoRespawn := True; Inc(gTotalMonsters); - if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); + if g_Game_IsNet then MH_SEND_MonsterSpawn(mon.UID); end; mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-15, FObj.Y+FObj.Rect.Y, D_RIGHT); if mon <> nil then begin - mon.SetState(STATE_GO); + mon.SetState(MONSTATE_GO); mon.FNoRespawn := True; Inc(gTotalMonsters); - if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); + if g_Game_IsNet then MH_SEND_MonsterSpawn(mon.UID); end; - if g_Game_IsNet then MH_SEND_CoopStats(gMonsters[sx].UID); + + if g_Game_IsNet then MH_SEND_CoopStats(); end; // Ó ýòèõ ìîíñòðîâ íåò òðóïîâ: @@ -2852,22 +3004,22 @@ _end: end; // Ñîâåðøåíèå àòàêè è ñòðåëüáû: - if (FState = STATE_ATTACK) or (FState = STATE_SHOOT) then + if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then if (FAnim[FCurAnim, FDirection] <> nil) then // Àíèìàöèÿ àòàêè åñòü - ìîæíî àòàêîâàòü if (FAnim[FCurAnim, FDirection].Played) then begin // Àíèìàöèÿ àòàêè çàêîí÷èëàñü => ïåðåõîäèì íà øàã - if FState = STATE_ATTACK then + if FState = MONSTATE_ATTACK then begin // Ñîñòîÿíèå - Àòàêà // Åñëè ìîíñòð íå Lost_Soul, òî ïîñëå àòàêè ïåðåõîäèì íà øàã: if FMonsterType <> MONSTER_SOUL then - SetState(STATE_GO); + SetState(MONSTATE_GO); end else // Ñîñòîÿíèå - Ñòðåëüáà begin // Ïåðåõîäèì íà øàã, åñëè íå íàäî ñòðåëÿòü åùå ðàç: if not FChainFire then - SetState(STATE_GO) + SetState(MONSTATE_GO) else begin // Íàäî ñòðåëÿòü åùå FChainFire := False; @@ -2887,7 +3039,7 @@ _end: (FAnim[FCurAnim, FDirection].TotalFrames div 2)) ) then begin // Àòàêè åùå íå áûëî è ýòî ñåðåäèíà àíèìàöèè àòàêè - if FState = STATE_ATTACK then + if FState = MONSTATE_ATTACK then begin // Ñîñòîÿíèå - Àòàêà // Åñëè ýòî Lost_Soul, òî ñáðàñûâàåì àíèìàöèþ àòàêè: if FMonsterType = MONSTER_SOUL then @@ -2899,7 +3051,7 @@ _end: if g_Weapon_Hit(@FObj, 15, FUID, HIT_SOME) <> 0 then // Lost_Soul óêóñèë êîãî-òî => ïåðåõîäèò íà øàã: if FMonsterType = MONSTER_SOUL then - SetState(STATE_GO); + SetState(MONSTATE_GO); MONSTER_FISH: // Ðûáà êóñàåò ïåðâîãî ïîïàâøåãîñÿ ñî çâóêîì: @@ -2923,7 +3075,7 @@ _end: sx := isCorpse(@FObj, True); if sx <> -1 then begin // Íàøëè, êîãî âîñêðåñèòü - gMonsters[sx].SetState(STATE_REVIVE); + gMonsters[sx].SetState(MONSTATE_REVIVE); g_Sound_PlayExAt('SOUND_MONSTER_SLOP', FObj.X, FObj.Y); // Âîñêðåøàòü - ñåáå âðåäèòü: {g_Weapon_HitUID(FUID, 5, 0, HIT_SOME);} @@ -3010,11 +3162,11 @@ _end: GetPos(FTargetUID, @o); mon.FTargetTime := 0; mon.FNoRespawn := True; - mon.SetState(STATE_GO); + mon.SetState(MONSTATE_GO); mon.shoot(@o, True); Inc(gTotalMonsters); - if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); + if g_Game_IsNet then MH_SEND_MonsterSpawn(mon.UID); end; end; end; @@ -3044,7 +3196,7 @@ _end: // Ïîñëåäíèé êàäð òåêóùåé àíèìàöèè: if FAnim[FCurAnim, FDirection].Counter = FAnim[FCurAnim, FDirection].Speed-1 then case FState of - STATE_GO, STATE_RUN, STATE_CLIMB, STATE_RUNOUT: + MONSTATE_GO, MONSTATE_RUN, MONSTATE_CLIMB, MONSTATE_RUNOUT: // Çâóêè ïðè ïåðåäâèæåíèè: case FMonsterType of MONSTER_CYBER: @@ -3067,7 +3219,7 @@ _end: end; if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_LIFTLEFT or PANEL_LIFTRIGHT) and - not ((FState = STATE_DEAD) or (FState = STATE_DIE)) then + not ((FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE)) then FObj.Vel.X := oldvelx; // Åñëè åñòü àíèìàöèÿ, òî ïóñòü îíà èäåò: @@ -3111,15 +3263,15 @@ begin // Ðûáû "ëåòàþò" òîëüêî â âîäå: if FMonsterType = MONSTER_FISH then if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then - if (FState <> STATE_DIE) and (FState <> STATE_DEAD) then + if (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) then fall := False; // Ëåòàþùèå ìîíòñðû: if ((FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_CACO)) and - (FState <> STATE_DIE) and - (FState <> STATE_DEAD) then + (FState <> MONSTATE_DIE) and + (FState <> MONSTATE_DEAD) then fall := False; // Ìåíÿåì ñêîðîñòü òîëüêî ïî ÷åòíûì êàäðàì: @@ -3150,7 +3302,7 @@ begin oldvelx := FObj.Vel.X; // Ñîïðîòèâëåíèå âîçäóõà äëÿ òðóïà: - if (FState = STATE_DIE) or (FState = STATE_DEAD) then + if (FState = MONSTATE_DIE) or (FState = MONSTATE_DEAD) then FObj.Vel.X := z_dec(FObj.Vel.X, 1); if FFireTime > 0 then @@ -3165,7 +3317,7 @@ begin end; // Ìåðòâûé íè÷åãî íå äåëàåò: - if (FState = STATE_DEAD) then + if (FState = MONSTATE_DEAD) then goto _end; // Âîçìîæíî, ñîçäàåì ïóçûðüêè â âîäå: @@ -3191,7 +3343,7 @@ begin // Åñëè ïðîøåë ïåðâûé êàäð àíèìàöèè âçðûâà áî÷êè, òî âçðûâ: if FMonsterType = MONSTER_BARREL then begin - if (FState = STATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and + if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and (FAnim[FCurAnim, FDirection].Counter = 0) then g_Weapon_Explode(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), FObj.Y+FObj.Rect.Y+FObj.Rect.Height-16, @@ -3235,8 +3387,8 @@ begin // Ïðîáóåì óâåðíóòüñÿ îò ëåòÿùåé ïóëè: if fall then - if (FState in [STATE_GO, STATE_RUN, STATE_RUNOUT, - STATE_ATTACK, STATE_SHOOT]) then + if (FState in [MONSTATE_GO, MONSTATE_RUN, MONSTATE_RUNOUT, + MONSTATE_ATTACK, MONSTATE_SHOOT]) then if g_Weapon_Danger(FUID, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, 50) then if (g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj)) and @@ -3244,7 +3396,7 @@ begin FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; case FState of - STATE_PAIN: // Ñîñòîÿíèå - Áîëü + MONSTATE_PAIN: // Ñîñòîÿíèå - Áîëü begin // Áîëü ñèëüíàÿ => ìîíñòð êðè÷èò: if FPain >= MONSTERTABLE[FMonsterType].Pain then @@ -3261,12 +3413,12 @@ begin // Áîëü óæå íå îøóòèìàÿ => èäåì äàëüøå: if FPain <= MONSTERTABLE[FMonsterType].MinPain then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); FPain := 0; end; end; - STATE_SLEEP: // Ñîñòîÿíèå - Ñîí + MONSTATE_SLEEP: // Ñîñòîÿíèå - Ñîí begin // Ñïèì: FSleep := FSleep + 1; @@ -3278,20 +3430,20 @@ begin goto _end; end; - STATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå + MONSTATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå begin // Æäåì: FSleep := FSleep - 1; end; - STATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) + MONSTATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) begin // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: if WordBool(st and MOVE_BLOCK) then begin Turn(); FSleep := 40; - SetState(STATE_RUNOUT); + SetState(MONSTATE_RUNOUT); goto _end; end; @@ -3300,7 +3452,7 @@ begin if (FMonsterType = MONSTER_VILE) then if isCorpse(@FObj, False) <> -1 then begin - SetState(STATE_ATTACK, ANIM_ATTACK2); + SetState(MONSTATE_ATTACK, ANIM_ATTACK2); FObj.Vel.X := 0; goto _end; @@ -3310,7 +3462,7 @@ begin if Abs(sx) < 40 then if FMonsterType <> MONSTER_FISH then begin - SetState(STATE_RUN); + SetState(MONSTATE_RUN); FSleep := 15; goto _end; @@ -3327,7 +3479,7 @@ begin begin // Ñòîèì íà òâåðäîì ïîëó èëè ñòóïåíè // Ïðûæîê ÷åðåç ñòåíó: FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; - SetState(STATE_CLIMB); + SetState(MONSTATE_CLIMB); end; end; @@ -3351,7 +3503,7 @@ begin end; // Ðûáå áîëüíî: - SetState(STATE_PAIN); + SetState(MONSTATE_PAIN); FPain := FPain + 50; end else // Ðûáà â âîäå @@ -3369,7 +3521,7 @@ begin // Âñïëûëè äî ïîâåðõíîñòè - ñòîï: FObj.Vel.Y := 0; // Ïëàâàåì òóäà-ñþäà: - SetState(STATE_RUN); + SetState(MONSTATE_RUN); FSleep := 20; end; end; @@ -3454,12 +3606,12 @@ begin FObj.Vel.X := 0; end; - STATE_RUN: // Ñîñòîÿíèå - Áåã + MONSTATE_RUN: // Ñîñòîÿíèå - Áåã begin // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: if WordBool(st and MOVE_BLOCK) then begin - SetState(STATE_RUNOUT); + SetState(MONSTATE_RUNOUT); FSleep := 40; goto _end; @@ -3470,7 +3622,7 @@ begin // Ïðîáåæàëè äîñòàòî÷íî èëè âðåçàëèñü â ñòåíó => ïåðåõîäèì íà øàã: if (FSleep <= 0) or (WordBool(st and MOVE_HITWALL) and ((FObj.Vel.Y+FObj.Accel.Y) = 0)) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); FSleep := 0; // Èíîãäà ðû÷èì: @@ -3492,7 +3644,7 @@ begin FObj.Vel.X := 0; end; - STATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî + MONSTATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî begin // Âûøëè èç ÁëîêÌîíà: if (not WordBool(st and MOVE_BLOCK)) and (FSleep > 0) then @@ -3503,7 +3655,7 @@ begin // Óáàæåëè äîñòàòî÷íî äàëåêî => ïåðåõîäèì íà øàã: if FSleep <= -18 then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); FSleep := 0; // Èíîãäà ðû÷èì: @@ -3525,19 +3677,19 @@ begin FObj.Vel.X := 0; end; - STATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) + MONSTATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) begin // Äîñòèãëè âûñøåé òî÷êè ïðûæêà èëè ñòåíà êîí÷èëàñü => ïåðåõîäèì íà øàã: if ((FObj.Vel.Y+FObj.Accel.Y) >= 0) or (not WordBool(st and MOVE_HITWALL)) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); FSleep := 0; // Ñòåíà íå êîí÷èëàñü => áåæèì îò íåå: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then begin - SetState(STATE_RUN); + SetState(MONSTATE_RUN); FSleep := 15; end; end; @@ -3556,14 +3708,14 @@ begin FObj.Vel.X := 0; end; - STATE_ATTACK, // Ñîñòîÿíèå - Àòàêà - STATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà + MONSTATE_ATTACK, // Ñîñòîÿíèå - Àòàêà + MONSTATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà begin // Lost_Soul âðåçàëñÿ â ñòåíó ïðè àòàêå => ïåðåõîäèò íà øàã: if FMonsterType = MONSTER_SOUL then begin if WordBool(st and (MOVE_HITWALL or MOVE_HITCEIL or MOVE_HITLAND)) then - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -3573,12 +3725,12 @@ begin FObj.Vel.X := z_dec(FObj.Vel.X, 1); // Íóæíî ñòðåëÿòü, à ìîíñòð - êîëäóí: - if (FMonsterType = MONSTER_VILE) and (FState = STATE_SHOOT) then + if (FMonsterType = MONSTER_VILE) and (FState = MONSTATE_SHOOT) then begin // Öåëü ïîãèáëà => èäåì äàëüøå: if not GetPos(FTargetUID, @o) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -3586,7 +3738,7 @@ begin // Öåëü íå âèäíî => èäåì äàëüøå: if not g_Look(@FObj, @o, FDirection) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -3594,7 +3746,7 @@ begin // Öåëü â âîäå - íå çàãîðèòñÿ => èäåì äàëüøå: if g_Obj_CollideWater(@o, 0, 0) then begin - SetState(STATE_GO); + SetState(MONSTATE_GO); goto _end; end; @@ -3605,11 +3757,11 @@ begin _end: // Ñîñòîÿíèå - Âîñêðåøåíèå: - if FState = STATE_REVIVE then + if FState = MONSTATE_REVIVE then if FAnim[FCurAnim, FDirection].Played then begin // Îáðàòíàÿ àíèìàöèÿ óìèðàíèÿ çàêîí÷èëàñü - èäåì äàëüøå: FAnim[FCurAnim, FDirection].Revert(False); - SetState(STATE_GO); + SetState(MONSTATE_GO); end; // Åñëè åñòü àíèìàöèÿ îãíÿ êîëäóíà - ïóñòü îíà èäåò: @@ -3617,12 +3769,12 @@ _end: vilefire.Update(); // Ñîñòîÿíèå - Óìèðàåò è òåêóùàÿ àíèìàöèÿ ïðîèãðàíà: - if (FState = STATE_DIE) and + if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection] <> nil) and (FAnim[FCurAnim, FDirection].Played) then begin // Óìåð: - SetState(STATE_DEAD); + SetState(MONSTATE_DEAD); // Ó ýòèõ ìîíñòðîâ íåò òðóïîâ: if (FMonsterType = MONSTER_PAIN) or @@ -3634,22 +3786,22 @@ _end: end; // Ñîâåðøåíèå àòàêè è ñòðåëüáû: - if (FState = STATE_ATTACK) or (FState = STATE_SHOOT) then + if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then if (FAnim[FCurAnim, FDirection] <> nil) then // Àíèìàöèÿ àòàêè åñòü - ìîæíî àòàêîâàòü if (FAnim[FCurAnim, FDirection].Played) then begin // Àíèìàöèÿ àòàêè çàêîí÷èëàñü => ïåðåõîäèì íà øàã - if FState = STATE_ATTACK then + if FState = MONSTATE_ATTACK then begin // Ñîñòîÿíèå - Àòàêà // Åñëè ìîíñòð íå Lost_Soul, òî ïîñëå àòàêè ïåðåõîäèì íà øàã: if FMonsterType <> MONSTER_SOUL then - SetState(STATE_GO); + SetState(MONSTATE_GO); end else // Ñîñòîÿíèå - Ñòðåëüáà begin // Ïåðåõîäèì íà øàã, åñëè íå íàäî ñòðåëÿòü åùå ðàç: if not FChainFire then - SetState(STATE_GO) + SetState(MONSTATE_GO) else begin // Íàäî ñòðåëÿòü åùå FChainFire := False; @@ -3669,7 +3821,7 @@ _end: (FAnim[FCurAnim, FDirection].TotalFrames div 2)) ) then begin // Àòàêè åùå íå áûëî è ýòî ñåðåäèíà àíèìàöèè àòàêè - if FState = STATE_ATTACK then + if FState = MONSTATE_ATTACK then begin // Ñîñòîÿíèå - Àòàêà // Åñëè ýòî Lost_Soul, òî ñáðàñûâàåì àíèìàöèþ àòàêè: if FMonsterType = MONSTER_SOUL then @@ -3681,7 +3833,7 @@ _end: if g_Weapon_Hit(@FObj, 15, FUID, HIT_SOME) <> 0 then // Lost_Soul óêóñèë êîãî-òî => ïåðåõîäèò íà øàã: if FMonsterType = MONSTER_SOUL then - SetState(STATE_GO); + SetState(MONSTATE_GO); MONSTER_FISH: g_Weapon_Hit(@FObj, 10, FUID, HIT_SOME); @@ -3733,7 +3885,7 @@ _end: // Ïîñëåäíèé êàäð òåêóùåé àíèìàöèè: if FAnim[FCurAnim, FDirection].Counter = FAnim[FCurAnim, FDirection].Speed-1 then case FState of - STATE_GO, STATE_RUN, STATE_CLIMB, STATE_RUNOUT: + MONSTATE_GO, MONSTATE_RUN, MONSTATE_CLIMB, MONSTATE_RUNOUT: // Çâóêè ïðè ïåðåäâèæåíèè: case FMonsterType of MONSTER_CYBER: @@ -3757,7 +3909,7 @@ _end: // Êîñòûëü äëÿ ïîòîêîâ if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_LIFTLEFT or PANEL_LIFTRIGHT) and - not ((FState = STATE_DEAD) or (FState = STATE_DIE)) then + not ((FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE)) then FObj.Vel.X := oldvelx; // Åñëè åñòü àíèìàöèÿ, òî ïóñòü îíà èäåò: @@ -3968,24 +4120,24 @@ begin case FMonsterType of MONSTER_FISH: begin - SetState(STATE_ATTACK); + SetState(MONSTATE_ATTACK); Result := True; end; MONSTER_DEMON: begin - SetState(STATE_ATTACK); + SetState(MONSTATE_ATTACK); g_Sound_PlayExAt('SOUND_MONSTER_DEMON_ATTACK', FObj.X, FObj.Y); Result := True; end; MONSTER_IMP: begin - SetState(STATE_ATTACK); + SetState(MONSTATE_ATTACK); g_Sound_PlayExAt('SOUND_MONSTER_IMP_ATTACK', FObj.X, FObj.Y); Result := True; end; MONSTER_SKEL, MONSTER_ROBO, MONSTER_CYBER: begin - SetState(STATE_ATTACK, ANIM_ATTACK2); + SetState(MONSTATE_ATTACK, ANIM_ATTACK2); g_Sound_PlayExAt('SOUND_MONSTER_SKEL_ATTACK', FObj.X, FObj.Y); Result := True; end; @@ -4068,19 +4220,19 @@ begin case FMonsterType of MONSTER_IMP, MONSTER_BARON, MONSTER_KNIGHT, MONSTER_CACO: begin - SetState(STATE_SHOOT); + SetState(MONSTATE_SHOOT); {nn} end; MONSTER_SKEL: begin - SetState(STATE_SHOOT); + SetState(MONSTATE_SHOOT); {nn} end; MONSTER_VILE: begin // Çàæèãàåì îãîíü tx := o^.X+o^.Rect.X+(o^.Rect.Width div 2); ty := o^.Y+o^.Rect.Y; - SetState(STATE_SHOOT); + SetState(MONSTATE_SHOOT); vilefire.Reset(); @@ -4089,7 +4241,7 @@ begin end; MONSTER_SOUL: begin // Ëåòèò â ñòîðîíó öåëè: - SetState(STATE_ATTACK); + SetState(MONSTATE_ATTACK); g_Sound_PlayExAt('SOUND_MONSTER_SOUL_ATTACK', FObj.X, FObj.Y); xd := tx-(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)); @@ -4109,7 +4261,7 @@ begin if FAmmo = 1 then g_Sound_PlayExAt('SOUND_MONSTER_MANCUB_ATTACK', FObj.X, FObj.Y); - SetState(STATE_SHOOT); + SetState(MONSTATE_SHOOT); end; else Exit; end; @@ -4119,7 +4271,7 @@ end; function TMonster.Live(): Boolean; begin - Result := (FState <> STATE_DIE) and (FState <> STATE_DEAD) and (FHealth > 0); + Result := (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) and (FHealth > 0); end; procedure TMonster.SetHealth(aH: Integer); @@ -4135,7 +4287,7 @@ end; procedure TMonster.WakeUp(); begin if g_Game_IsClient then Exit; - SetState(STATE_GO); + SetState(MONSTATE_GO); FTargetTime := MAX_ATM; WakeUpSound(); end; @@ -4222,6 +4374,7 @@ begin end; end; + procedure TMonster.LoadState(var Mem: TBinMemoryReader); var i: Integer; @@ -4238,8 +4391,13 @@ begin begin raise EBinSizeError.Create('TMonster.LoadState: Wrong Monster Signature'); end; + if (uidMap[FUID] <> nil) and (uidMap[FUID] <> self) then raise Exception.Create('internal error in monster loader (0)'); + uidMap[FUID] := nil; // UID ìîíñòðà: Mem.ReadWord(FUID); + //if (arrIdx = -1) then raise Exception.Create('internal error in monster loader'); + if (uidMap[FUID] <> nil) then raise Exception.Create('internal error in monster loader (1)'); + uidMap[FUID] := self; // Íàïðàâëåíèå: Mem.ReadByte(b); if b = 1 then @@ -4344,8 +4502,7 @@ procedure TMonster.CatchFire(Attacker: Word); begin FFireTime := 100; FFireAttacker := Attacker; - if g_Game_IsNet and g_Game_IsServer then - MH_SEND_MonsterState(FUID); + if g_Game_IsNet and g_Game_IsServer then MH_SEND_MonsterState(FUID); end; procedure TMonster.OnFireFlame(Times: DWORD = 1); @@ -4363,7 +4520,7 @@ begin Anim := TAnimation.Create(id, False, 3); Anim.Alpha := 0; g_GFX_OnceAnim(Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(Anim.Width div 2), - Obj.Y+8+Random(8+Times*2)+IfThen(FState = STATE_DEAD, 16, 0), Anim, ONCEANIM_SMOKE); + Obj.Y+8+Random(8+Times*2)+IfThen(FState = MONSTATE_DEAD, 16, 0), Anim, ONCEANIM_SMOKE); Anim.Free(); end; end; @@ -4371,36 +4528,61 @@ end; // ////////////////////////////////////////////////////////////////////////// // +// throws on invalid uid +function g_Mons_ByIdx (uid: Integer): TMonster; inline; +begin + result := g_Mons_ByIdx_NC(uid); + if (result = nil) then raise Exception.Create('g_Mons_ByIdx: invalid monster id'); +end; + +// can return null +function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline; +begin + if (uid < 0) or (uid > High(gMonsters)) then begin result := nil; exit; end; + result := gMonsters[uid]; +end; + +function g_Mons_TotalCount (): Integer; inline; +begin + result := Length(gMonsters); +end; + + function g_Mons_ForEach (cb: TEachMonsterCB): Boolean; var idx: Integer; + mon: TMonster; begin result := false; if (gMonsters = nil) or not assigned(cb) then exit; for idx := 0 to High(gMonsters) do begin - if (gMonsters[idx] <> nil) then + mon := gMonsters[idx]; + if (mon <> nil) then begin - result := cb(idx, gMonsters[idx]); + result := cb(mon); if result then exit; end; end; end; -// throws on invalid uid -function g_Mons_ByIdx (uid: Integer): TMonster; inline; -begin - result := g_Mons_ByIdx_NC(uid); - if (result = nil) then raise Exception.Create('g_Mons_ByIdx: invalid monster id'); -end; - - -// can return null -function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline; +function g_Mons_ForEachAlive (cb: TEachMonsterCB): Boolean; +var + idx: Integer; + mon: TMonster; begin - if (uid < 0) or (uid > High(gMonsters)) then begin result := nil; exit; end; - result := gMonsters[uid]; + result := false; + if (gMonsters = nil) or not assigned(cb) then exit; + for idx := 0 to High(gMonsters) do + begin + mon := gMonsters[idx]; + if (mon <> nil) and mon.Live then + begin + result := cb(mon); + if result then exit; + end; + end; end; @@ -4408,26 +4590,27 @@ function g_Mons_IsAnyAliveAt (x, y: Integer; width, height: Integer): Boolean; function monsCollCheck (mon: TMonster; atag: Integer): Boolean; begin - result := (mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj)); + result := mon.Live;// and g_Obj_Collide(x, y, width, height, @mon.Obj)); end; var idx: Integer; + mon: TMonster; begin result := false; if (width < 1) or (height < 1) then exit; - if gmon_debug_use_sqaccel then begin - result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil); + result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil); end else begin for idx := 0 to High(gMonsters) do begin - if (gMonsters[idx] <> nil) and gMonsters[idx].Live then + mon := gMonsters[idx]; + if (mon <> nil) and mon.Live then begin - if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then + if g_Obj_Collide(x, y, width, height, @mon.Obj) then begin result := true; exit; @@ -4442,29 +4625,29 @@ function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonst function monsCollCheck (mon: TMonster; atag: Integer): Boolean; begin - result := false; - if g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon.arrIdx, mon); + result := cb(mon); end; var idx: Integer; + mon: TMonster; begin result := false; if (width < 1) or (height < 1) then exit; - if gmon_debug_use_sqaccel then begin - result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil); + result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil); end else begin for idx := 0 to High(gMonsters) do begin - if (gMonsters[idx] <> nil) and gMonsters[idx].Live then + mon := gMonsters[idx]; + if (mon <> nil) and mon.Live then begin - if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then + if g_Obj_Collide(x, y, width, height, @mon.Obj) then begin - result := cb(idx, gMonsters[idx]); + result := cb(mon); if result then exit; end; end; @@ -4473,40 +4656,42 @@ begin end; -function g_Mons_ForEachAtAlive (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean; +function g_Mons_ForEachAliveAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean; function monsCollCheck (mon: TMonster; atag: Integer): Boolean; begin - result := false; - if mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon.arrIdx, mon); + //result := false; + //if mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon); + if mon.Live then result := cb(mon) else result := false; end; var idx: Integer; + mon: TMonster; begin result := false; if (width < 1) or (height < 1) then exit; - if gmon_debug_use_sqaccel then begin if (width = 1) and (height = 1) then begin - result := (monsTree.pointQuery(x, y, monsCollCheck) <> nil); + result := (monsGrid.forEachAtPoint(x, y, monsCollCheck) <> nil); end else begin - result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil); + result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil); end; end else begin for idx := 0 to High(gMonsters) do begin - if (gMonsters[idx] <> nil) and gMonsters[idx].Live then + mon := gMonsters[idx]; + if (mon <> nil) and mon.Live then begin - if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then + if g_Obj_Collide(x, y, width, height, @mon.Obj) then begin - result := cb(idx, gMonsters[idx]); + result := cb(mon); if result then exit; end; end;