I decided to clean up MS4's updateNpcAI. I removed some checks and combined some with other checks.
I did some basic testing and it seems to be working well. If you notice any problems let me know. Let's get it cleaned up!
Some of the changes:
Removed all the checks for the npc num, might have to re-add this. Will test.
Attack on sight: Checks for target before looping through players.
Attack on sight: If it finds a target then it exits' the player loop.
Combined following a player and the npc attacking stuff.
Code:
Private Sub UpdateNpcAI()
Dim i As Long, n As Long
Dim MapNum As Long, MapNpcNum As Long
Dim NpcNum As Long, Target As Long
Dim TickCount As Long
Dim Damage As Long
Dim DistanceX As Long
Dim DistanceY As Long
Dim DidWalk As Boolean
For MapNum = 1 To MAX_MAPS
If PlayersOnMap(MapNum) = YES Then
TickCount = GetTickCount
For MapNpcNum = 1 To MAX_MAP_NPCS
NpcNum = MapNpc(MapNum, MapNpcNum).Num
' Make sure theres a npc with the map
If NpcNum > 0 Then
' Get the target
Target = MapNpc(MapNum, MapNpcNum).Target
' /////////////////////////////////////////
' // This is used for ATTACKING ON SIGHT //
' /////////////////////////////////////////
' If the npc is a attack on sight, search for a player on the map
If Npc(NpcNum).Behavior = NPC_BEHAVIOR_ATTACKONSIGHT Or Npc(NpcNum).Behavior = NPC_BEHAVIOR_GUARD Then
' First check if they don't have a target before looping...
If Target = 0 Then
For i = 1 To High_Index
If IsPlaying(i) Then
If GetPlayerMap(i) = MapNum Then
If GetPlayerAccess(i) <= ADMIN_MONITOR Then
n = Npc(NpcNum).Range
DistanceX = MapNpc(MapNum, MapNpcNum).X - GetPlayerX(i)
DistanceY = MapNpc(MapNum, MapNpcNum).Y - GetPlayerY(i)
' Make sure we get a positive value
If DistanceX < 0 Then DistanceX = -DistanceX
If DistanceY < 0 Then DistanceY = -DistanceY
' Are they in range? if so GET'M!
If DistanceX <= n Then
If DistanceY <= n Then
If Npc(NpcNum).Behavior = NPC_BEHAVIOR_ATTACKONSIGHT Or GetPlayerPK(i) = YES Then
If LenB(Trim$(Npc(NpcNum).AttackSay)) > 0 Then
Call PlayerMsg(i, "A " & Trim$(Npc(NpcNum).Name) & " says, '" & Trim$(Npc(NpcNum).AttackSay) & "' to you.", SayColor)
End If
MapNpc(MapNum, MapNpcNum).Target = i
Exit For
End If
End If
End If
End If
End If
End If
Next
End If
End If
' /////////////////////////////////////////////
' // This is used for NPC walking/targetting //
' /////////////////////////////////////////////
' Check to see if its time for the npc to walk
If Npc(NpcNum).Behavior <> NPC_BEHAVIOR_SHOPKEEPER Then
' Check to see if we are following a player or not
If Target > 0 Then
' Check if the player is even playing, if so follow'm
If IsPlaying(Target) Then
If GetPlayerMap(Target) = MapNum Then
DidWalk = False
i = Int(Rnd * 4)
' Lets move the npc
Select Case i
Case 0
' Up
If MapNpc(MapNum, MapNpcNum).Y > GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_UP) Then
Call NpcMove(MapNum, MapNpcNum, DIR_UP, MOVING_WALKING)
DidWalk = True
End If
End If
' Down
If MapNpc(MapNum, MapNpcNum).Y < GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_DOWN) Then
Call NpcMove(MapNum, MapNpcNum, DIR_DOWN, MOVING_WALKING)
DidWalk = True
End If
End If
' Left
If MapNpc(MapNum, MapNpcNum).X > GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_LEFT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_LEFT, MOVING_WALKING)
DidWalk = True
End If
End If
' Right
If MapNpc(MapNum, MapNpcNum).X < GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_RIGHT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_RIGHT, MOVING_WALKING)
DidWalk = True
End If
End If
Case 1
' Right
If MapNpc(MapNum, MapNpcNum).X < GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_RIGHT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_RIGHT, MOVING_WALKING)
DidWalk = True
End If
End If
' Left
If MapNpc(MapNum, MapNpcNum).X > GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_LEFT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_LEFT, MOVING_WALKING)
DidWalk = True
End If
End If
' Down
If MapNpc(MapNum, MapNpcNum).Y < GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_DOWN) Then
Call NpcMove(MapNum, MapNpcNum, DIR_DOWN, MOVING_WALKING)
DidWalk = True
End If
End If
' Up
If MapNpc(MapNum, MapNpcNum).Y > GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_UP) Then
Call NpcMove(MapNum, MapNpcNum, DIR_UP, MOVING_WALKING)
DidWalk = True
End If
End If
Case 2
' Down
If MapNpc(MapNum, MapNpcNum).Y < GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_DOWN) Then
Call NpcMove(MapNum, MapNpcNum, DIR_DOWN, MOVING_WALKING)
DidWalk = True
End If
End If
' Up
If MapNpc(MapNum, MapNpcNum).Y > GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_UP) Then
Call NpcMove(MapNum, MapNpcNum, DIR_UP, MOVING_WALKING)
DidWalk = True
End If
End If
' Right
If MapNpc(MapNum, MapNpcNum).X < GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_RIGHT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_RIGHT, MOVING_WALKING)
DidWalk = True
End If
End If
' Left
If MapNpc(MapNum, MapNpcNum).X > GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_LEFT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_LEFT, MOVING_WALKING)
DidWalk = True
End If
End If
Case 3
' Left
If MapNpc(MapNum, MapNpcNum).X > GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_LEFT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_LEFT, MOVING_WALKING)
DidWalk = True
End If
End If
' Right
If MapNpc(MapNum, MapNpcNum).X < GetPlayerX(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_RIGHT) Then
Call NpcMove(MapNum, MapNpcNum, DIR_RIGHT, MOVING_WALKING)
DidWalk = True
End If
End If
' Up
If MapNpc(MapNum, MapNpcNum).Y > GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_UP) Then
Call NpcMove(MapNum, MapNpcNum, DIR_UP, MOVING_WALKING)
DidWalk = True
End If
End If
' Down
If MapNpc(MapNum, MapNpcNum).Y < GetPlayerY(Target) And Not DidWalk Then
If CanNpcMove(MapNum, MapNpcNum, DIR_DOWN) Then
Call NpcMove(MapNum, MapNpcNum, DIR_DOWN, MOVING_WALKING)
DidWalk = True
End If
End If
End Select
' Check if we can't move and if player is behind something and if we can just switch dirs
If Not DidWalk Then
If MapNpc(MapNum, MapNpcNum).X - 1 = GetPlayerX(Target) And MapNpc(MapNum, MapNpcNum).Y = GetPlayerY(Target) Then
If MapNpc(MapNum, MapNpcNum).Dir <> DIR_LEFT Then
Call NpcDir(MapNum, MapNpcNum, DIR_LEFT)
End If
DidWalk = True
End If
End If
If Not DidWalk Then
If MapNpc(MapNum, MapNpcNum).X + 1 = GetPlayerX(Target) And MapNpc(MapNum, MapNpcNum).Y = GetPlayerY(Target) Then
If MapNpc(MapNum, MapNpcNum).Dir <> DIR_RIGHT Then
Call NpcDir(MapNum, MapNpcNum, DIR_RIGHT)
End If
DidWalk = True
End If
End If
If Not DidWalk Then
If MapNpc(MapNum, MapNpcNum).X = GetPlayerX(Target) And MapNpc(MapNum, MapNpcNum).Y - 1 = GetPlayerY(Target) Then
If MapNpc(MapNum, MapNpcNum).Dir <> DIR_UP Then
Call NpcDir(MapNum, MapNpcNum, DIR_UP)
End If
DidWalk = True
End If
End If
If Not DidWalk Then
If MapNpc(MapNum, MapNpcNum).X = GetPlayerX(Target) And MapNpc(MapNum, MapNpcNum).Y + 1 = GetPlayerY(Target) Then
If MapNpc(MapNum, MapNpcNum).Dir <> DIR_DOWN Then
Call NpcDir(MapNum, MapNpcNum, DIR_DOWN)
End If
DidWalk = True
End If
End If
' We could not move so player must be behind something, walk randomly.
If Not DidWalk Then
i = Int(Rnd * 2)
If i = 1 Then
i = Int(Rnd * 4)
If CanNpcMove(MapNum, MapNpcNum, i) Then
Call NpcMove(MapNum, MapNpcNum, i, MOVING_WALKING)
End If
End If
End If
' /////////////////////////////////////////////
' // This is used for npcs to attack players //
' /////////////////////////////////////////////
' Can the npc attack the player?
If CanNpcAttackPlayer(MapNpcNum, Target) Then
If Not CanPlayerBlockHit(Target) Then
Damage = Npc(NpcNum).Stat(Stats.Strength) - GetPlayerProtection(Target)
Call NpcAttackPlayer(MapNpcNum, Target, Damage)
Else
Call PlayerMsg(Target, "Your " & Trim$(Item(GetPlayerInvItemNum(Target, GetPlayerEquipmentSlot(Target, Shield))).Name) & " blocks the " & Trim$(Npc(NpcNum).Name) & "'s hit!", BrightCyan)
End If
End If
Else
MapNpc(MapNum, MapNpcNum).Target = 0
End If
Else
MapNpc(MapNum, MapNpcNum).Target = 0
End If
Else
If Int(Rnd * 4) = 1 Then
i = Int(Rnd * 4)
If CanNpcMove(MapNum, MapNpcNum, i) Then
Call NpcMove(MapNum, MapNpcNum, i, MOVING_WALKING)
End If
End If
End If
End If
' ////////////////////////////////////////////
' // This is used for regenerating NPC's HP //
' ////////////////////////////////////////////
If TickCount > GiveNPCHPTimer + 10000 Then
If MapNpc(MapNum, MapNpcNum).Vital(Vitals.HP) > 0 Then
MapNpc(MapNum, MapNpcNum).Vital(Vitals.HP) = MapNpc(MapNum, MapNpcNum).Vital(Vitals.HP) + GetNpcVitalRegen(NpcNum, Vitals.HP)
' Check if they have more then they should and if so just set it to max
If MapNpc(MapNum, MapNpcNum).Vital(Vitals.HP) > GetNpcMaxVital(NpcNum, Vitals.HP) Then
MapNpc(MapNum, MapNpcNum).Vital(Vitals.HP) = GetNpcMaxVital(NpcNum, Vitals.HP)
End If
End If
GiveNPCHPTimer = TickCount
End If
End If
' //////////////////////////////////////
' // This is used for spawning an NPC //
' //////////////////////////////////////
' Check if we are supposed to spawn an npc or not
If MapNpc(MapNum, MapNpcNum).Num = 0 Then
If Map(MapNum).Npc(MapNpcNum) > 0 Then
If TickCount > MapNpc(MapNum, MapNpcNum).SpawnWait + (Npc(Map(MapNum).Npc(MapNpcNum)).SpawnSecs * 1000) Then
Call SpawnNpc(MapNpcNum, MapNum)
End If
End If
End If
Next
End If
DoEvents
Next
End Sub