it tells me "Compile error: Method or data member not found" Then it highlights .Quest in If NPC(npcNum).Quest = YES Then under the function Function CanPlayerAttackNpc(ByVal attacker As Long, ByVal mapNpcNum As Long, Optional ByVal IsSpell As Boolean = False) As Boolean >! ``` Option Explicit >! ' ################################ ' ## Basic Calculations ## ' ################################ >! Function GetPlayerMaxVital(ByVal Index As Long, ByVal Vital As Vitals) As Long If Index > MAX_PLAYERS Then Exit Function Select Case Vital Case HP Select Case GetPlayerClass(Index) Case 1 ' Warrior GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Endurance) / 2)) * 15 + 150 Case 2 ' Mage GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Endurance) / 2)) * 5 + 65 Case Else ' Anything else - Warrior by default GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Endurance) / 2)) * 15 + 150 End Select Case MP Select Case GetPlayerClass(Index) Case 1 ' Warrior GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Intelligence) / 2)) * 5 + 25 Case 2 ' Mage GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Intelligence) / 2)) * 30 + 85 Case Else ' Anything else - Warrior by default GetPlayerMaxVital = ((GetPlayerLevel(Index) / 2) + (GetPlayerStat(Index, Intelligence) / 2)) * 5 + 25 End Select End Select End Function >! Function GetPlayerVitalRegen(ByVal Index As Long, ByVal Vital As Vitals) As Long Dim i As Long >! ' Prevent subscript out of range If IsPlaying(Index) = False Or Index MAX_PLAYERS Then GetPlayerVitalRegen = 0 Exit Function End If >! Select Case Vital Case HP i = (GetPlayerStat(Index, Stats.Willpower) * 0.8) + 6 Case MP i = (GetPlayerStat(Index, Stats.Willpower) / 4) + 12.5 End Select >! If i < 2 Then i = 2 GetPlayerVitalRegen = i End Function >! Function GetPlayerDamage(ByVal Index As Long) As Long Dim weaponNum As Long GetPlayerDamage = 0 >! ' Check for subscript out of range If IsPlaying(Index) = False Or Index MAX_PLAYERS Then Exit Function End If If GetPlayerEquipment(Index, Weapon) > 0 Then weaponNum = GetPlayerEquipment(Index, Weapon) GetPlayerDamage = 0.085 * 5 * GetPlayerStat(Index, Strength) * Item(weaponNum).Data2 + (GetPlayerLevel(Index) / 5) Else GetPlayerDamage = 0.085 * 5 * GetPlayerStat(Index, Strength) + (GetPlayerLevel(Index) / 5) End If >! End Function >! Function GetNpcMaxVital(ByVal npcNum As Long, ByVal Vital As Vitals) As Long Dim x As Long >! ' Prevent subscript out of range If npcNum MAX_NPCS Then GetNpcMaxVital = 0 Exit Function End If >! Select Case Vital Case HP GetNpcMaxVital = NPC(npcNum).HP Case MP GetNpcMaxVital = 30 + (NPC(npcNum).Stat(Intelligence) * 10) + 2 End Select >! End Function >! Function GetNpcVitalRegen(ByVal npcNum As Long, ByVal Vital As Vitals) As Long Dim i As Long >! 'Prevent subscript out of range If npcNum MAX_NPCS Then GetNpcVitalRegen = 0 Exit Function End If >! Select Case Vital Case HP i = (NPC(npcNum).Stat(Stats.Willpower) * 0.8) + 6 Case MP i = (NPC(npcNum).Stat(Stats.Willpower) / 4) + 12.5 End Select GetNpcVitalRegen = i >! End Function >! Function GetNpcDamage(ByVal npcNum As Long) As Long GetNpcDamage = 0.085 * 5 * NPC(npcNum).Stat(Stats.Strength) * NPC(npcNum).Damage + (NPC(npcNum).Level / 5) End Function >! ' ############################### ' ## Luck-based rates ## ' ############################### >! Public Function CanPlayerBlock(ByVal Index As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanPlayerBlock = False >! rate = 0 ' TODO : make it based on shield lulz End Function >! Public Function CanPlayerCrit(ByVal Index As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanPlayerCrit = False >! rate = GetPlayerStat(Index, Agility) / 52.08 rndNum = RAND(1, 100) If rndNum ! Public Function CanPlayerDodge(ByVal Index As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanPlayerDodge = False >! rate = GetPlayerStat(Index, Agility) / 83.3 rndNum = RAND(1, 100) If rndNum ! Public Function CanPlayerParry(ByVal Index As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanPlayerParry = False >! rate = GetPlayerStat(Index, Strength) * 0.25 rndNum = RAND(1, 100) If rndNum ! Public Function CanNpcBlock(ByVal npcNum As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanNpcBlock = False >! rate = 0 ' TODO : make it based on shield lol End Function >! Public Function CanNpcCrit(ByVal npcNum As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanNpcCrit = False >! rate = NPC(npcNum).Stat(Stats.Agility) / 52.08 rndNum = RAND(1, 100) If rndNum ! Public Function CanNpcDodge(ByVal npcNum As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanNpcDodge = False >! rate = NPC(npcNum).Stat(Stats.Agility) / 83.3 rndNum = RAND(1, 100) If rndNum ! Public Function CanNpcParry(ByVal npcNum As Long) As Boolean Dim rate As Long Dim rndNum As Long >! CanNpcParry = False >! rate = NPC(npcNum).Stat(Stats.Strength) * 0.25 rndNum = RAND(1, 100) If rndNum ! ' ################################### ' ## Player Attacking NPC ## ' ################################### >! Public Sub TryPlayerAttackNpc(ByVal Index As Long, ByVal mapNpcNum As Long) Dim blockAmount As Long Dim npcNum As Long Dim mapNum As Long Dim Damage As Long >! Damage = 0 >! ' Can we attack the npc? If CanPlayerAttackNpc(Index, mapNpcNum) Then mapNum = GetPlayerMap(Index) npcNum = MapNpc(mapNum).NPC(mapNpcNum).Num ' check if NPC can avoid the attack If CanNpcDodge(npcNum) Then SendActionMsg mapNum, "Dodge!", Pink, 1, (MapNpc(mapNum).NPC(mapNpcNum).x * 32), (MapNpc(mapNum).NPC(mapNpcNum).y * 32) Exit Sub End If If CanNpcParry(npcNum) Then SendActionMsg mapNum, "Parry!", Pink, 1, (MapNpc(mapNum).NPC(mapNpcNum).x * 32), (MapNpc(mapNum).NPC(mapNpcNum).y * 32) Exit Sub End If >! ' Get the damage we can do Damage = GetPlayerDamage(Index) ' if the npc blocks, take away the block amount blockAmount = CanNpcBlock(mapNpcNum) Damage = Damage - blockAmount ' take away armour Damage = Damage - RAND(1, (NPC(npcNum).Stat(Stats.Agility) * 2)) ' randomise from 1 to max hit Damage = RAND(1, Damage) ' * 1.5 if it's a crit! If CanPlayerCrit(Index) Then Damage = Damage * 1.5 SendActionMsg mapNum, "Critical!", BrightCyan, 1, (GetPlayerX(Index) * 32), (GetPlayerY(Index) * 32) End If If Damage > 0 Then Call PlayerAttackNpc(Index, mapNpcNum, Damage) Else Call PlayerMsg(Index, "Your attack does nothing.", BrightRed) End If End If End Sub >! Public Function CanPlayerAttackNpc(ByVal attacker As Long, ByVal mapNpcNum As Long, Optional ByVal IsSpell As Boolean = False) As Boolean Dim mapNum As Long Dim npcNum As Long Dim NpcX As Long Dim NpcY As Long Dim attackspeed As Long >! ' Check for subscript out of range If IsPlaying(attacker) = False Or mapNpcNum MAX_MAP_NPCS Then Exit Function End If >! ' Check for subscript out of range If MapNpc(GetPlayerMap(attacker)).NPC(mapNpcNum).Num ! mapNum = GetPlayerMap(attacker) npcNum = MapNpc(mapNum).NPC(mapNpcNum).Num ' Make sure the npc isn't already dead If MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) ! ' Make sure they are on the same map If IsPlaying(attacker) Then ' exit out early If IsSpell Then If npcNum > 0 Then If NPC(npcNum).Behaviour NPC_BEHAVIOUR_FRIENDLY And NPC(npcNum).Behaviour NPC_BEHAVIOUR_SHOPKEEPER Then CanPlayerAttackNpc = True Exit Function End If End If End If >! ' attack speed from weapon If GetPlayerEquipment(attacker, Weapon) > 0 Then attackspeed = Item(GetPlayerEquipment(attacker, Weapon)).Speed Else attackspeed = 1000 End If >! If npcNum > 0 And GetTickCount > TempPlayer(attacker).AttackTimer + attackspeed Then ' Check if at same coordinates Select Case GetPlayerDir(attacker) Case DIR_UP NpcX = MapNpc(mapNum).NPC(mapNpcNum).x NpcY = MapNpc(mapNum).NPC(mapNpcNum).y + 1 Case DIR_DOWN NpcX = MapNpc(mapNum).NPC(mapNpcNum).x NpcY = MapNpc(mapNum).NPC(mapNpcNum).y - 1 Case DIR_LEFT NpcX = MapNpc(mapNum).NPC(mapNpcNum).x + 1 NpcY = MapNpc(mapNum).NPC(mapNpcNum).y Case DIR_RIGHT NpcX = MapNpc(mapNum).NPC(mapNpcNum).x - 1 NpcY = MapNpc(mapNum).NPC(mapNpcNum).y End Select >! If NpcX = GetPlayerX(attacker) Then If NpcY = GetPlayerY(attacker) Then If NPC(npcNum).Behaviour NPC_BEHAVIOUR_FRIENDLY And NPC(npcNum).Behaviour NPC_BEHAVIOUR_SHOPKEEPER Then CanPlayerAttackNpc = True Else 'ALATAR If NPC(npcNum).Behaviour = NPC_BEHAVIOUR_FRIENDLY Then Call CheckTasks(attacker, QUEST_TYPE_GOTALK, npcNum) Call CheckTasks(attacker, QUEST_TYPE_GOGIVE, npcNum) Call CheckTasks(attacker, QUEST_TYPE_GOGET, npcNum) If NPC(npcNum).Quest = YES Then If CanStartQuest(attacker, NPC(npcNum).QuestNum) Then 'if can start show the request message (chat1) QuestMessage attacker, NPC(npcNum).QuestNum, Trim$(Quest(NPC(npcNum).QuestNum).Chat(1)), NPC(npcNum).QuestNum Exit Function End If If QuestInProgress(attacker, NPC(npcNum).QuestNum) Then 'if the quest is in progress show the meanwhile message (chat2) PlayerMsg attacker, Trim$(NPC(npcNum).Name) + ": " + Trim$(Quest(NPC(npcNum).QuestNum).Chat(2)), BrightGreen 'QuestMessage attacker, NPC(npcNum).QuestNum, Trim$(Quest(NPC(npcNum).QuestNum).Chat(2)), 0 Exit Function End If End If If NPC(npcNum).Quest = NO Then If NPC(npcNum).Convo = False Then If Len(Trim$(NPC(npcNum).AttackSay)) > 0 Then PlayerMsg attacker, Trim$(NPC(npcNum).Name) + ": " + Trim$(Quest(NPC(npcNum).QuestNum).Chat(2)), BrightGreen End If Else InitChat attacker, mapNum, mapNpcNum End If Exit Function End If End If End If End If End If End If End If >! End Function >! Public Sub PlayerAttackNpc(ByVal attacker As Long, ByVal mapNpcNum As Long, ByVal Damage As Long, Optional ByVal spellnum As Long, Optional ByVal overTime As Boolean = False) Dim Name As String Dim exp As Long Dim n As Long Dim i As Long Dim STR As Long Dim DEF As Long Dim mapNum As Long Dim npcNum As Long Dim Buffer As clsBuffer >! ' Check for subscript out of range If IsPlaying(attacker) = False Or mapNpcNum MAX_MAP_NPCS Or Damage < 0 Then Exit Sub End If >! mapNum = GetPlayerMap(attacker) npcNum = MapNpc(mapNum).NPC(mapNpcNum).Num Name = Trim$(NPC(npcNum).Name) ' Check for weapon n = 0 >! If GetPlayerEquipment(attacker, Weapon) > 0 Then n = GetPlayerEquipment(attacker, Weapon) End If ' set the regen timer TempPlayer(attacker).stopRegen = True TempPlayer(attacker).stopRegenTimer = GetTickCount >! If Damage >= MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) Then SendActionMsg GetPlayerMap(attacker), "-" & MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP), BrightRed, 1, (MapNpc(mapNum).NPC(mapNpcNum).x * 32), (MapNpc(mapNum).NPC(mapNpcNum).y * 32) SendBlood GetPlayerMap(attacker), MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y ' send the sound If spellnum > 0 Then SendMapSound attacker, MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y, SoundEntity.seSpell, spellnum ' send animation If n > 0 Then If Not overTime Then If spellnum = 0 Then Call SendAnimation(mapNum, Item(GetPlayerEquipment(attacker, Weapon)).Animation, MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y) End If End If >! ' Calculate exp to give attacker exp = NPC(npcNum).exp >! ' Make sure we dont get less then 0 If exp < 0 Then exp = 1 End If >! ' in party? If TempPlayer(attacker).inParty > 0 Then ' pass through party sharing function Party_ShareExp TempPlayer(attacker).inParty, exp, attacker Else ' no party - keep exp for self GivePlayerEXP attacker, exp End If 'Drop the goods if they get it n = Int(Rnd * NPC(npcNum).DropChance) + 1 >! If n = 1 Then Call SpawnItem(NPC(npcNum).DropItem, NPC(npcNum).DropItemValue, mapNum, MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y) End If >! ' Now set HP to 0 so we know to actually kill them in the server loop (this prevents subscript out of range) MapNpc(mapNum).NPC(mapNpcNum).Num = 0 MapNpc(mapNum).NPC(mapNpcNum).SpawnWait = GetTickCount MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) = 0 ' clear DoTs and HoTs For i = 1 To MAX_DOTS With MapNpc(mapNum).NPC(mapNpcNum).DoT(i) .Spell = 0 .Timer = 0 .Caster = 0 .StartTime = 0 .Used = False End With With MapNpc(mapNum).NPC(mapNpcNum).HoT(i) .Spell = 0 .Timer = 0 .Caster = 0 .StartTime = 0 .Used = False End With Next Call CheckTasks(attacker, QUEST_TYPE_GOSLAY, npcNum) ' send death to the map Set Buffer = New clsBuffer Buffer.WriteLong SNpcDead Buffer.WriteLong mapNpcNum SendDataToMap mapNum, Buffer.ToArray() Set Buffer = Nothing 'Loop through entire map and purge NPC from targets For i = 1 To Player_HighIndex If IsPlaying(i) And IsConnected(i) Then If Player(i).Map = mapNum Then If TempPlayer(i).targetType = TARGET_TYPE_NPC Then If TempPlayer(i).target = mapNpcNum Then TempPlayer(i).target = 0 TempPlayer(i).targetType = TARGET_TYPE_NONE SendTarget i End If End If End If End If Next Else ' NPC not dead, just do the damage MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) = MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) - Damage >! ' Check for a weapon and say damage SendActionMsg mapNum, "-" & Damage, BrightRed, 1, (MapNpc(mapNum).NPC(mapNpcNum).x * 32), (MapNpc(mapNum).NPC(mapNpcNum).y * 32) SendBlood GetPlayerMap(attacker), MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y ' send the sound If spellnum > 0 Then SendMapSound attacker, MapNpc(mapNum).NPC(mapNpcNum).x, MapNpc(mapNum).NPC(mapNpcNum).y, SoundEntity.seSpell, spellnum ' send animation If n > 0 Then If Not overTime Then If spellnum = 0 Then Call SendAnimation(mapNum, Item(GetPlayerEquipment(attacker, Weapon)).Animation, 0, 0, TARGET_TYPE_NPC, mapNpcNum) End If End If >! ' Set the NPC target to the player MapNpc(mapNum).NPC(mapNpcNum).targetType = 1 ' player MapNpc(mapNum).NPC(mapNpcNum).target = attacker >! ' Now check for guard ai and if so have all onmap guards come after'm If NPC(MapNpc(mapNum).NPC(mapNpcNum).Num).Behaviour = NPC_BEHAVIOUR_GUARD Then For i = 1 To MAX_MAP_NPCS If MapNpc(mapNum).NPC(i).Num = MapNpc(mapNum).NPC(mapNpcNum).Num Then MapNpc(mapNum).NPC(i).target = attacker MapNpc(mapNum).NPC(i).targetType = 1 ' player End If Next End If ' set the regen timer MapNpc(mapNum).NPC(mapNpcNum).stopRegen = True MapNpc(mapNum).NPC(mapNpcNum).stopRegenTimer = GetTickCount ' if stunning spell, stun the npc If spellnum > 0 Then If Spell(spellnum).StunDuration > 0 Then StunNPC mapNpcNum, mapNum, spellnum ' DoT If Spell(spellnum).Duration > 0 Then AddDoT_Npc mapNum, mapNpcNum, spellnum, attacker End If End If SendMapNpcVitals mapNum, mapNpcNum End If >! If spellnum = 0 Then ' Reset attack timer TempPlayer(attacker).AttackTimer = GetTickCount End If End Sub >! ' ################################### ' ## NPC Attacking Player ## ' ################################### >! Public Sub TryNpcAttackPlayer(ByVal mapNpcNum As Long, ByVal Index As Long) Dim mapNum As Long, npcNum As Long, blockAmount As Long, Damage As Long >! ' Can the npc attack the player? If CanNpcAttackPlayer(mapNpcNum, Index) Then mapNum = GetPlayerMap(Index) npcNum = MapNpc(mapNum).NPC(mapNpcNum).Num ' check if PLAYER can avoid the attack If CanPlayerDodge(Index) Then SendActionMsg mapNum, "Dodge!", Pink, 1, (Player(Index).x * 32), (Player(Index).y * 32) Exit Sub End If If CanPlayerParry(Index) Then SendActionMsg mapNum, "Parry!", Pink, 1, (Player(Index).x * 32), (Player(Index).y * 32) Exit Sub End If >! ' Get the damage we can do Damage = GetNpcDamage(npcNum) ' if the player blocks, take away the block amount blockAmount = CanPlayerBlock(Index) Damage = Damage - blockAmount ' take away armour Damage = Damage - RAND(1, (GetPlayerStat(Index, Agility) * 2)) ' randomise for up to 10% lower than max hit Damage = RAND(1, Damage) ' * 1.5 if crit hit If CanNpcCrit(Index) Then Damage = Damage * 1.5 SendActionMsg mapNum, "Critical!", BrightCyan, 1, (MapNpc(mapNum).NPC(mapNpcNum).x * 32), (MapNpc(mapNum).NPC(mapNpcNum).y * 32) End If >! If Damage > 0 Then Call NpcAttackPlayer(mapNpcNum, Index, Damage) End If End If End Sub >! Function CanNpcAttackPlayer(ByVal mapNpcNum As Long, ByVal Index As Long) As Boolean Dim mapNum As Long Dim npcNum As Long >! ' Check for subscript out of range If mapNpcNum MAX_MAP_NPCS Or Not IsPlaying(Index) Then Exit Function End If >! ' Check for subscript out of range If MapNpc(GetPlayerMap(Index)).NPC(mapNpcNum).Num ! mapNum = GetPlayerMap(Index) npcNum = MapNpc(mapNum).NPC(mapNpcNum).Num >! ' Make sure the npc isn't already dead If MapNpc(mapNum).NPC(mapNpcNum).Vital(Vitals.HP) ! ' Make sure npcs dont attack more then once a second If GetTickCount < MapNpc(mapNum).NPC(mapNpcNum).AttackTimer + 1000 Then Exit Function End If >! ' Make sure we dont attack the player if they are switching maps If TempPlayer(Index).GettingMap = YES Then Exit Function End If >! MapNpc(mapNum).NPC(mapNpcNum).AttackTimer = GetTickCount >! ' Make sure they are on the same map If IsPlaying(Index) Then If npcNum > 0 Then >! ' Check if at same coordinates If (GetPlayerY(Index) + 1 = MapNpc(mapNum).NPC(mapNpcNum).y) And (GetPlayerX(Index) = MapNpc(mapNum).NPC(mapNpcNum).x) Then CanNpcAttackPlayer = True Else If (GetPlayerY(Index) - 1 = MapNpc(mapNum).NPC(mapNpcNum).y) And (GetPlayerX(Index) = MapNpc(mapNum).NPC(mapNpcNum).x) Then CanNpcAttackPlayer = True Else If (GetPlayerY(Index) = MapNpc(mapNum).NPC(mapNpcNum).y) And (GetPlayerX(Index) + 1 = MapNpc(mapNum).NPC(mapNpcNum).x) Then CanNpcAttackPlayer = True Else If (GetPlayerY(Index) = MapNpc(mapNum).NPC(mapNpcNum).y) And (GetPlayerX(Index) - 1 = MapNpc(mapNum).NPC(mapNpcNum).x) Then CanNpcAttackPlayer = True End If End If End If End If End If End If End Function >! Sub NpcAttackPlayer(ByVal mapNpcNum As Long, ByVal victim As Long, ByVal Damage As Long) Dim Name As String Dim exp As Long Dim mapNum As Long Dim i As Long Dim Buffer As clsBuffer >! ' Check for subscript out of range If mapNpcNum MAX_MAP_NPCS Or IsPlaying(victim) = False Then Exit Sub End If >! ' Check for subscript out of range If MapNpc(GetPlayerMap(victim)).NPC(mapNpcNum).Num ! mapNum = GetPlayerMap(victim) Name = Trim$(NPC(MapNpc(mapNum).NPC(mapNpcNum).Num).Name) ' Send this packet so they can see the npc attacking Set Buffer = New clsBuffer Buffer.WriteLong SNpcAttack Buffer.WriteLong mapNpcNum SendDataToMap mapNum, Buffer.ToArray() Set Buffer = Nothing If Damage 0 Then SendPartyVitals TempPlayer(victim).inParty, victim ' send the sound SendMapSound victim, GetPlayerX(victim), GetPlayerY(victim), SoundEntity.seNpc, MapNpc(mapNum).NPC(mapNpcNum).Num ' Say damage SendActionMsg GetPlayerMap(victim), "-" & Damage, BrightRed, 1, (GetPlayerX(victim) * 32), (GetPlayerY(victim) * 32) SendBlood GetPlayerMap(victim), GetPlayerX(victim), GetPlayerY(victim) ' set the regen timer TempPlayer(victim).stopRegen = True TempPlayer(victim).stopRegenTimer = GetTickCount End If >! End Sub >! ' ################################### ' ## Player Attacking Player ## ' ################################### >! Public Sub TryPlayerAttackPlayer(ByVal attacker As Long, ByVal victim As Long) Dim blockAmount As Long Dim npcNum As Long Dim mapNum As Long Dim Damage As Long >! Damage = 0 >! ' Can we attack the npc? If CanPlayerAttackPlayer(attacker, victim) Then mapNum = GetPlayerMap(attacker) ' check if NPC can avoid the attack If CanPlayerDodge(victim) Then SendActionMsg mapNum, "Dodge!", Pink, 1, (GetPlayerX(victim) * 32), (GetPlayerY(victim) * 32) Exit Sub End If If CanPlayerParry(victim) Then SendActionMsg mapNum, "Parry!", Pink, 1, (GetPlayerX(victim) * 32), (GetPlayerY(victim) * 32) Exit Sub End If >! ' Get the damage we can do Damage = GetPlayerDamage(attacker) ' if the npc blocks, take away the block amount blockAmount = CanPlayerBlock(victim) Damage = Damage - blockAmount ' take away armour Damage = Damage - RAND(1, (GetPlayerStat(victim, Agility) * 2)) ' randomise for up to 10% lower than max hit Damage = RAND(1, Damage) ' * 1.5 if can crit If CanPlayerCrit(attacker) Then Damage = Damage * 1.5 SendActionMsg mapNum, "Critical!", BrightCyan, 1, (GetPlayerX(attacker) * 32), (GetPlayerY(attacker) * 32) End If >! If Damage > 0 Then Call PlayerAttackPlayer(attacker, victim, Damage) Else Call PlayerMsg(attacker, "Your attack does nothing.", BrightRed) End If End If End Sub >! Function CanPlayerAttackPlayer(ByVal attacker As Long, ByVal victim As Long, Optional ByVal IsSpell As Boolean = False) As Boolean >! If Not IsSpell Then ' Check attack timer If GetPlayerEquipment(attacker, Weapon) > 0 Then If GetTickCount < TempPlayer(attacker).AttackTimer + Item(GetPlayerEquipment(attacker, Weapon)).Speed Then Exit Function Else If GetTickCount < TempPlayer(attacker).AttackTimer + 1000 Then Exit Function End If End If >! ' Check for subscript out of range If Not IsPlaying(victim) Then Exit Function >! ' Make sure they are on the same map If Not GetPlayerMap(attacker) = GetPlayerMap(victim) Then Exit Function >! ' Make sure we dont attack the player if they are switching maps If TempPlayer(victim).GettingMap = YES Then Exit Function >! If Not IsSpell Then ' Check if at same coordinates Select Case GetPlayerDir(attacker) Case DIR_UP If Not ((GetPlayerY(victim) + 1 = GetPlayerY(attacker)) And (GetPlayerX(victim) = GetPlayerX(attacker))) Then Exit Function Case DIR_DOWN If Not ((GetPlayerY(victim) - 1 = GetPlayerY(attacker)) And (GetPlayerX(victim) = GetPlayerX(attacker))) Then Exit Function Case DIR_LEFT If Not ((GetPlayerY(victim) = GetPlayerY(attacker)) And (GetPlayerX(victim) + 1 = GetPlayerX(attacker))) Then Exit Function Case DIR_RIGHT If Not ((GetPlayerY(victim) = GetPlayerY(attacker)) And (GetPlayerX(victim) - 1 = GetPlayerX(attacker))) Then Exit Function Case Else Exit Function End Select End If >! ' Check if map is attackable If Not Map(GetPlayerMap(attacker)).Moral = MAP_MORAL_NONE Then If GetPlayerPK(victim) = NO Then Call PlayerMsg(attacker, "This is a safe zone!", BrightRed) Exit Function End If End If >! ' Make sure they have more then 0 hp If GetPlayerVital(victim, Vitals.HP) ! ' Check to make sure that they dont have access If GetPlayerAccess(attacker) > ADMIN_MONITOR Then Call PlayerMsg(attacker, "Admins cannot attack other players.", BrightBlue) Exit Function End If >! ' Check to make sure the victim isn't an admin If GetPlayerAccess(victim) > ADMIN_MONITOR Then Call PlayerMsg(attacker, "You cannot attack " & GetPlayerName(victim) & "!", BrightRed) Exit Function End If >! ' Make sure attacker is high enough level If GetPlayerLevel(attacker) < 10 Then Call PlayerMsg(attacker, "You are below level 10, you cannot attack another player yet!", BrightRed) Exit Function End If >! ' Make sure victim is high enough level If GetPlayerLevel(victim) < 10 Then Call PlayerMsg(attacker, GetPlayerName(victim) & " is below level 10, you cannot attack this player yet!", BrightRed) Exit Function End If >! CanPlayerAttackPlayer = True End Function >! Sub PlayerAttackPlayer(ByVal attacker As Long, ByVal victim As Long, ByVal Damage As Long, Optional ByVal spellnum As Long = 0) Dim exp As Long Dim n As Long Dim i As Long Dim Buffer As clsBuffer >! ' Check for subscript out of range If IsPlaying(attacker) = False Or IsPlaying(victim) = False Or Damage < 0 Then Exit Sub End If >! ' Check for weapon n = 0 >! If GetPlayerEquipment(attacker, Weapon) > 0 Then n = GetPlayerEquipment(attacker, Weapon) End If ' set the regen timer TempPlayer(attacker).stopRegen = True TempPlayer(attacker).stopRegenTimer = GetTickCount >! If Damage >= GetPlayerVital(victim, Vitals.HP) Then SendActionMsg GetPlayerMap(victim), "-" & GetPlayerVital(victim, Vitals.HP), BrightRed, 1, (GetPlayerX(victim) * 32), (GetPlayerY(victim) * 32) ' send the sound If spellnum > 0 Then SendMapSound victim, GetPlayerX(victim), GetPlayerY(victim), SoundEntity.seSpell, spellnum ' Player is dead Call GlobalMsg(GetPlayerName(victim) & " has been killed by " & GetPlayerName(attacker), BrightRed) ' Calculate exp to give attacker exp = (GetPlayerExp(victim) \ 10) >! ' Make sure we dont get less then 0 If exp < 0 Then exp = 0 End If >! If exp = 0 Then Call PlayerMsg(victim, "You lost no exp.", BrightRed) Call PlayerMsg(attacker, "You received no exp.", BrightBlue) Else Call SetPlayerExp(victim, GetPlayerExp(victim) - exp) SendEXP victim Call PlayerMsg(victim, "You lost " & exp & " exp.", BrightRed) ' check if we're in a party If TempPlayer(attacker).inParty > 0 Then ' pass through party exp share function Party_ShareExp TempPlayer(attacker).inParty, exp, attacker Else ' not in party, get exp for self GivePlayerEXP attacker, exp End If End If ' purge target info of anyone who targetted dead guy For i = 1 To Player_HighIndex If IsPlaying(i) And IsConnected(i) Then If Player(i).Map = GetPlayerMap(attacker) Then If TempPlayer(i).target = TARGET_TYPE_PLAYER Then If TempPlayer(i).target = victim Then TempPlayer(i).target = 0 TempPlayer(i).targetType = TARGET_TYPE_NONE SendTarget i End If End If End If End If Next >! If GetPlayerPK(victim) = NO Then If GetPlayerPK(attacker) = NO Then Call SetPlayerPK(attacker, YES) Call SendPlayerData(attacker) Call GlobalMsg(GetPlayerName(attacker) & " has been deemed a Player Killer!!!", BrightRed) End If >! Else Call GlobalMsg(GetPlayerName(victim) & " has paid the price for being a Player Killer!!!", BrightRed) End If Call CheckTasks(attacker, QUEST_TYPE_GOKILL, victim) Call OnDeath(victim) Else ' Player not dead, just do the damage Call SetPlayerVital(victim, Vitals.HP, GetPlayerVital(victim, Vitals.HP) - Damage) Call SendVital(victim, Vitals.HP) ' send vitals to party if in one If TempPlayer(victim).inParty > 0 Then SendPartyVitals TempPlayer(victim).inParty, victim ' send the sound If spellnum > 0 Then SendMapSound victim, GetPlayerX(victim), GetPlayerY(victim), SoundEntity.seSpell, spellnum SendActionMsg GetPlayerMap(victim), "-" & Damage, BrightRed, 1, (GetPlayerX(victim) * 32), (GetPlayerY(victim) * 32) SendBlood GetPlayerMap(victim), GetPlayerX(victim), GetPlayerY(victim) ' set the regen timer TempPlayer(victim).stopRegen = True TempPlayer(victim).stopRegenTimer = GetTickCount 'if a stunning spell, stun the player If spellnum > 0 Then If Spell(spellnum).StunDuration > 0 Then StunPlayer victim, spellnum ' DoT If Spell(spellnum).Duration > 0 Then AddDoT_Player victim, spellnum, attacker End If End If End If >! ' Reset attack timer TempPlayer(attacker).AttackTimer = GetTickCount End Sub >! ' ############ ' ## Spells ## ' ############ >! Public Sub BufferSpell(ByVal Index As Long, ByVal spellslot As Long) Dim spellnum As Long Dim MPCost As Long Dim LevelReq As Long Dim mapNum As Long Dim SpellCastType As Long Dim ClassReq As Long Dim AccessReq As Long Dim Range As Long Dim HasBuffered As Boolean Dim targetType As Byte Dim target As Long ' Prevent subscript out of range If spellslot MAX_PLAYER_SPELLS Then Exit Sub spellnum = GetPlayerSpell(Index, spellslot) mapNum = GetPlayerMap(Index) If spellnum MAX_SPELLS Then Exit Sub ' Make sure player has the spell If Not HasSpell(Index, spellnum) Then Exit Sub ' see if cooldown has finished If TempPlayer(Index).SpellCD(spellslot) > GetTickCount Then PlayerMsg Index, "Spell hasn't cooled down yet!", BrightRed Exit Sub End If >! MPCost = Spell(spellnum).MPCost >! ' Check if they have enough MP If GetPlayerVital(Index, Vitals.MP) < MPCost Then Call PlayerMsg(Index, "Not enough mana!", BrightRed) Exit Sub End If LevelReq = Spell(spellnum).LevelReq >! ' Make sure they are the right level If LevelReq > GetPlayerLevel(Index) Then Call PlayerMsg(Index, "You must be level " & LevelReq & " to cast this spell.", BrightRed) Exit Sub End If AccessReq = Spell(spellnum).AccessReq ' make sure they have the right access If AccessReq > GetPlayerAccess(Index) Then Call PlayerMsg(Index, "You must be an administrator to cast this spell.", BrightRed) Exit Sub End If ClassReq = Spell(spellnum).ClassReq ' make sure the classreq > 0 If ClassReq > 0 Then ' 0 = no req If ClassReq GetPlayerClass(Index) Then Call PlayerMsg(Index, "Only " & CheckGrammar(Trim$(Class(ClassReq).Name)) & " can use this spell.", BrightRed) Exit Sub End If End If ' find out what kind of spell it is! self cast, target or AOE If Spell(spellnum).Range > 0 Then ' ranged attack, single target or aoe? If Not Spell(spellnum).IsAoE Then SpellCastType = 2 ' targetted Else SpellCastType = 3 ' targetted aoe End If Else If Not Spell(spellnum).IsAoE Then SpellCastType = 0 ' self-cast Else SpellCastType = 1 ' self-cast AoE End If End If targetType = TempPlayer(Index).targetType target = TempPlayer(Index).target Range = Spell(spellnum).Range HasBuffered = False Select Case SpellCastType Case 0, 1 ' self-cast & self-cast AOE HasBuffered = True Case 2, 3 ' targeted & targeted AOE ' check if have target If Not target > 0 Then PlayerMsg Index, "You do not have a target.", BrightRed End If If targetType = TARGET_TYPE_PLAYER Then ' if have target, check in range If Not isInRange(Range, GetPlayerX(Index), GetPlayerY(Index), GetPlayerX(target), GetPlayerY(target)) Then PlayerMsg Index, "Target not in range.", BrightRed El ```