From d80c7b5f3535c40785895c82fb27d3479a6bceec Mon Sep 17 00:00:00 2001 From: Alexis Caraballo Date: Sun, 3 Mar 2024 03:58:10 -0300 Subject: [PATCH] Fix seguro NPC Fixes #514 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se elimina el chequeo de distancia para ser "dueño" de un NPC. Tenía un bug fácil de arreglar pero charlando con los game master pensamos que sería mejor otra estrategia. Ahora es por tiempo: 10 segundos (por defecto) desde el último ataque. Esto es configurable desde intervalos.ini Igualmente al irte del rango de visión del NPC dejás de ser el dueño. Arreglé otro errorcito que si pasabas por al lado de un NPC que tenía dueño, ignoraba todas las validaciones y te golpeaba igual. --- Codigo/AI_NPC.bas | 16 ++++---- Codigo/Admin.bas | 1 + Codigo/Declares.bas | 1 + Codigo/EffectProvoked.cls | 1 + Codigo/FileIO.bas | 1 + Codigo/FrmInterv.frm | 1 + Codigo/GameLogic.bas | 4 ++ Codigo/MODULO_NPCs.bas | 79 +++++++++++++++++++++++--------------- Codigo/Modulo_UsUaRiOs.bas | 5 ++- Codigo/Protocol.bas | 2 +- Codigo/SistemaCombate.bas | 2 + Codigo/clsIniManager.cls | 12 +++--- intervalos.ini | 1 + 13 files changed, 82 insertions(+), 44 deletions(-) diff --git a/Codigo/AI_NPC.bas b/Codigo/AI_NPC.bas index ab0ffb9d7..cb72a7fa2 100644 --- a/Codigo/AI_NPC.bas +++ b/Codigo/AI_NPC.bas @@ -600,9 +600,7 @@ Private Sub AI_AtacarUsuarioObjetivo(ByVal AtackerNpcIndex As Integer) Call AnimacionIdle(AtackerNpcIndex, True) If UserIndexFront > 0 Then If UserList(UserIndexFront).flags.Muerto = 0 Then - If UserList(UserIndexFront).Faccion.Status = 1 And (.NPCtype = e_NPCType.GuardiaReal) Then - - Else + If EsEnemigo(AtackerNpcIndex, UserIndexFront) Then Call NpcAtacaUser(AtackerNpcIndex, UserIndexFront, tHeading) End If End If @@ -1281,22 +1279,26 @@ Private Function EsEnemigo(ByVal NpcIndex As Integer, ByVal UserIndex As Integer 100 If NpcIndex = 0 Or UserIndex = 0 Then Exit Function -102 With NpcList(NpcIndex) + EsEnemigo = True +102 With NpcList(NpcIndex) + ' Si el NPC tiene un atacante 104 If .flags.AttackedBy <> vbNullString Then + ' Si el usuario actual es el atacante 106 EsEnemigo = (UserIndex = NameIndex(.flags.AttackedBy).ArrayIndex) 108 If EsEnemigo Then Exit Function + ' Si no es el atacante, preguntamos si el NPC puede atacarlo +109 EsEnemigo = CanAttackNotOwner(NpcIndex, UserIndex) End If 110 Select Case .flags.AIAlineacion Case e_Alineacion.Real -112 EsEnemigo = (Status(UserIndex) Mod 2) <> 1 +112 EsEnemigo = EsEnemigo And (Status(UserIndex) Mod 2) <> 1 114 Case e_Alineacion.Caos -116 EsEnemigo = (Status(UserIndex) Mod 2) <> 0 +116 EsEnemigo = EsEnemigo And (Status(UserIndex) Mod 2) <> 0 118 Case e_Alineacion.ninguna -120 EsEnemigo = True ' Ok. No hay nada especial para hacer, cualquiera puede ser enemigo! End Select diff --git a/Codigo/Admin.bas b/Codigo/Admin.bas index ac3eb30d4..c44d28165 100644 --- a/Codigo/Admin.bas +++ b/Codigo/Admin.bas @@ -93,6 +93,7 @@ Public IntervaloMagiaGolpe As Long Public IntervaloGolpeMagia As Long Public IntervaloUserPuedeCastear As Long Public IntervaloTrabajarExtraer As Long +Public IntervaloNpcOwner As Long Public IntervaloTrabajarConstruir As Long diff --git a/Codigo/Declares.bas b/Codigo/Declares.bas index 84c683e16..b447ddcb2 100644 --- a/Codigo/Declares.bas +++ b/Codigo/Declares.bas @@ -2553,6 +2553,7 @@ Public Type t_NPCFlags ' UseAINow As Boolean No se usa, borrar de la DB!!!! Sound As Integer AttackedBy As String + AttackedTime As Long AttackedFirstBy As String backup As Byte RespawnOrigPos As Byte diff --git a/Codigo/EffectProvoked.cls b/Codigo/EffectProvoked.cls index e5b1f6162..bf53535dd 100644 --- a/Codigo/EffectProvoked.cls +++ b/Codigo/EffectProvoked.cls @@ -68,6 +68,7 @@ Public Sub Setup(ByVal SourceIndex As Integer, ByVal SourceType As e_ReferenceTy If SourceType = eUser Then Call SetUserRef(NpcList(TargetIndex).TargetUser, SourceIndex) NpcList(TargetIndex).flags.AttackedBy = UserList(SourceIndex).name + NpcList(TargetIndex).flags.AttackedTime = GetTickCount Else Call SetNpcRef(NpcList(TargetIndex).TargetNPC, SourceIndex) End If diff --git a/Codigo/FileIO.bas b/Codigo/FileIO.bas index 030cb7489..f54c469e4 100644 --- a/Codigo/FileIO.bas +++ b/Codigo/FileIO.bas @@ -2701,6 +2701,7 @@ Sub LoadIntervalos() 'TODO : Agregar estos intervalos al form!!! 206 IntervaloMagiaGolpe = val(Lector.GetValue("INTERVALOS", "IntervaloMagiaGolpe")) 208 IntervaloGolpeMagia = val(Lector.GetValue("INTERVALOS", "IntervaloGolpeMagia")) +209 IntervaloNpcOwner = val(Lector.GetValue("INTERVALOS", "IntervaloNpcOwner", "10000")) 'frmMain.tLluvia.Interval = val(Lector.GetValue("INTERVALOS", "IntervaloPerdidaStaminaLluvia")) 'FrmInterv.txtIntervaloPerdidaStaminaLluvia.Text = frmMain.tLluvia.Interval diff --git a/Codigo/FrmInterv.frm b/Codigo/FrmInterv.frm index 31d914cdc..85f735696 100644 --- a/Codigo/FrmInterv.frm +++ b/Codigo/FrmInterv.frm @@ -896,6 +896,7 @@ Private Sub Command2_Click() 140 Call WriteVar(IniPath & "intervalo.ini", "INTERVALOS", "IntervaloTrabajarExtraer", CStr(IntervaloTrabajarExtraer)) 142 Call WriteVar(IniPath & "intervalo.ini", "INTERVALOS", "IntervaloTrabajarConstruir", CStr(IntervaloTrabajarConstruir)) 144 Call WriteVar(IniPath & "intervalo.ini", "INTERVALOS", "IntervaloUserPuedeAtacar", CStr(IntervaloUserPuedeAtacar)) +145 Call WriteVar(IniPath & "intervalo.ini", "INTERVALOS", "IntervaloNpcOwner", CStr(IntervaloNpcOwner)) 'Call WriteVar(IniPath & "intervalo.ini", "INTERVALOS", "IntervaloPerdidaStaminaLluvia", frmMain.tLluvia.Interval) 146 MsgBox "Los intervalos se han guardado sin problemas" diff --git a/Codigo/GameLogic.bas b/Codigo/GameLogic.bas index 63ed448bb..631c4ebdc 100644 --- a/Codigo/GameLogic.bas +++ b/Codigo/GameLogic.bas @@ -1587,6 +1587,10 @@ Sub LookatTile(ByVal UserIndex As Integer, ByVal Map As Integer, ByVal X As Inte End If End If + + If EsGM(UserIndex) And GetOwnedBy(TempCharIndex) <> 0 Then + estatus = estatus & " | Owned by " & NpcList(TempCharIndex).flags.AttackedBy + End If 456 estatus = estatus & ">" diff --git a/Codigo/MODULO_NPCs.bas b/Codigo/MODULO_NPCs.bas index 01a923ed4..971a7dd73 100644 --- a/Codigo/MODULO_NPCs.bas +++ b/Codigo/MODULO_NPCs.bas @@ -319,6 +319,7 @@ Sub ResetNpcFlags(ByVal NpcIndex As Integer) 102 .AfectaParalisis = 0 104 .AguaValida = 0 106 .AttackedBy = vbNullString +107 .AttackedTime = 0 108 .AttackedFirstBy = vbNullString 112 .backup = 0 116 .Domable = 0 @@ -1674,6 +1675,7 @@ Sub DoFollow(ByVal NpcIndex As Integer, ByVal UserName As String) player = NameIndex(username) If IsValidUserRef(player) Then 114 .flags.AttackedBy = username +115 .flags.AttackedTime = GetTickCount 116 .targetUser = player 118 .flags.Follow = True 120 Call SetMovement(NpcIndex, e_TipoAI.NpcDefensa) @@ -2134,36 +2136,26 @@ UserCanAttackNpc.TurnPK = False End If If NpcList(NpcIndex).flags.team = 0 Then - If NpcList(NpcIndex).flags.AttackedBy <> "" Then - Dim CurrentOwner As t_UserReference - Dim CurrentOwnerIndex As Integer - Dim AttackedNpcIndex As Integer - - CurrentOwner = NameIndex(NpcList(NpcIndex).flags.AttackedBy) - If IsValidUserRef(CurrentOwner) Then - CurrentOwnerIndex = CurrentOwner.ArrayIndex - - If CurrentOwnerIndex <> UserIndex And IsValidNpcRef(UserList(CurrentOwnerIndex).flags.NPCAtacado) Then - If UserList(CurrentOwnerIndex).flags.NPCAtacado.ArrayIndex = NpcIndex And _ - UserList(CurrentOwnerIndex).flags.Muerto = 0 And _ - (Status(CurrentOwnerIndex) = Ciudadano Or Status(CurrentOwnerIndex) = Armada Or Status(CurrentOwnerIndex) = Consejo) And _ - Distancia(UserList(CurrentOwnerIndex).pos, UserList(UserIndex).pos) <= 12 And _ - (UserList(UserIndex).GuildIndex = 0 Or UserList(UserIndex).GuildIndex <> UserList(CurrentOwnerIndex).GuildIndex) And _ - (UserList(UserIndex).Grupo.EnGrupo = False Or UserList(UserIndex).Grupo.id <> UserList(CurrentOwnerIndex).Grupo.id) Then - - - If UserList(UserIndex).flags.Seguro Then - UserCanAttackNpc.result = eRemoveSafeCitizenNpc - Exit Function - Else - UserCanAttackNpc.TurnPK = True - UserCanAttackNpc.CanAttack = True - UserCanAttackNpc.result = eAttackCitizenNpc - Exit Function - End If - End If - End If - End If + Dim CurrentOwnerIndex As Integer: CurrentOwnerIndex = GetOwnedBy(NpcIndex) + If CurrentOwnerIndex <> 0 Then + If CurrentOwnerIndex <> UserIndex And IsValidNpcRef(UserList(CurrentOwnerIndex).flags.NPCAtacado) Then + If UserList(CurrentOwnerIndex).flags.NPCAtacado.ArrayIndex = NpcIndex And _ + UserList(CurrentOwnerIndex).flags.Muerto = 0 And _ + (Status(CurrentOwnerIndex) = Ciudadano Or Status(CurrentOwnerIndex) = Armada Or Status(CurrentOwnerIndex) = consejo) And _ + (UserList(UserIndex).GuildIndex = 0 Or UserList(UserIndex).GuildIndex <> UserList(CurrentOwnerIndex).GuildIndex) And _ + (UserList(UserIndex).Grupo.EnGrupo = False Or UserList(UserIndex).Grupo.Id <> UserList(CurrentOwnerIndex).Grupo.Id) Then + + If UserList(UserIndex).flags.Seguro Then + UserCanAttackNpc.Result = eRemoveSafeCitizenNpc + Exit Function + Else + UserCanAttackNpc.TurnPK = True + UserCanAttackNpc.CanAttack = True + UserCanAttackNpc.Result = eAttackCitizenNpc + Exit Function + End If + End If + End If End If End If End If @@ -2386,3 +2378,30 @@ Public Function GetDefenseBonus(ByVal NpcIndex As Integer) As Integer GetDefenseBonus = NpcList(NpcIndex).Modifiers.DefenseBonus End Function +' Retorna el usuario que esta atacando al NPC actualmente (medido con tiempo) +Public Function GetOwnedBy(ByVal NpcIndex As Integer) As Integer + GetOwnedBy = 0 + With NpcList(NpcIndex).flags + If .AttackedBy = vbNullString Then Exit Function + If GetTickCount - .AttackedTime > IntervaloNpcOwner Then Exit Function + Dim Attacker As t_UserReference: Attacker = NameIndex(.AttackedBy) + If Not IsValidUserRef(Attacker) Then Exit Function + GetOwnedBy = Attacker.ArrayIndex + End With +End Function + +' Retorna si un NPC puede atacar un usuario diferente al que lo esta atacando +Public Function CanAttackNotOwner(ByVal NpcIndex As Integer, ByVal UserIndex As Integer) As Boolean + Dim AttackResult As t_AttackInteractionResult + AttackResult = UserCanAttackNpc(UserIndex, NpcIndex) + + ' Si el usuario puede atacar al NPC + If AttackResult.CanAttack Then + ' Lo atacamos solo si puede atacar sin hacerse PK (no lo forzamos a hacerse PK) + CanAttackNotOwner = AttackResult.TurnPK + Else + ' En caso que el usuario no pueda atacar al NPC, este debe ignorarlo a el + ' Excepto que no pueda atacar por los siguientes motivos: esta montado, esta fuera de su campo de vision + CanAttackNotOwner = AttackResult.Result = eMounted Or AttackResult.Result = eOutOfRange + End If +End Function diff --git a/Codigo/Modulo_UsUaRiOs.bas b/Codigo/Modulo_UsUaRiOs.bas index 916793425..67eec5b1c 100644 --- a/Codigo/Modulo_UsUaRiOs.bas +++ b/Codigo/Modulo_UsUaRiOs.bas @@ -1934,7 +1934,10 @@ Sub NPCAtacado(ByVal NpcIndex As Integer, ByVal UserIndex As Integer, Optional B 104 If Not IsSet(NpcList(npcIndex).flags.StatusMask, eTaunted) And NpcList(npcIndex).Movement <> Estatico And NpcList(npcIndex).flags.AttackedFirstBy = vbNullString Then 106 Call SetUserRef(NpcList(npcIndex).TargetUser, UserIndex) 108 NpcList(NpcIndex).Hostile = 1 -110 If AffectsOwner Then NpcList(NpcIndex).flags.AttackedBy = UserList(UserIndex).name +110 If AffectsOwner Then + NpcList(NpcIndex).flags.AttackedBy = UserList(UserIndex).name + NpcList(NpcIndex).flags.AttackedTime = GetTickCount + End If End If 'Guarda el NPC que estas atacando ahora. diff --git a/Codigo/Protocol.bas b/Codigo/Protocol.bas index 99a3a6262..b83a3a12d 100644 --- a/Codigo/Protocol.bas +++ b/Codigo/Protocol.bas @@ -3294,7 +3294,7 @@ Private Sub HandleWorkLeftClick(ByVal UserIndex As Integer) Exit Sub End If -564 If LenB(NpcList(tN).flags.AttackedBy) <> 0 Then +564 If GetOwnedBy(tN) <> 0 Then 566 Call WriteConsoleMsg(UserIndex, "No puedes domar una criatura que esta luchando con un jugador.", e_FontTypeNames.FONTTYPE_INFO) Exit Sub End If diff --git a/Codigo/SistemaCombate.bas b/Codigo/SistemaCombate.bas index c092d5332..0fc1700a8 100644 --- a/Codigo/SistemaCombate.bas +++ b/Codigo/SistemaCombate.bas @@ -2081,6 +2081,7 @@ Sub AllMascotasAtacanUser(ByVal victim As Integer, ByVal Maestro As Integer) If IsValidNpcRef(.MascotasIndex(iCount)) Then 108 If IsSet(NpcList(mascotaIndex).flags.BehaviorFlags, e_BehaviorFlags.eAttackUsers) Then 110 NpcList(mascotaIndex).flags.AttackedBy = UserList(victim).Name +111 NpcList(mascotaIndex).flags.AttackedTime = GetTickCount 112 Call SetUserRef(NpcList(mascotaIndex).TargetUser, victim) 114 Call SetMovement(mascotaIndex, e_TipoAI.NpcDefensa) 116 NpcList(mascotaIndex).Hostile = 0 @@ -2126,6 +2127,7 @@ Public Sub AllMascotasAtacanNPC(ByVal NpcIndex As Integer, ByVal UserIndex As In 110 Call SetNpcRef(.TargetNPC, NpcIndex) 112 Call SetMovement(mascotaIdx, e_TipoAI.NpcAtacaNpc) NpcList(NpcIndex).flags.AttackedBy = UserList(UserIndex).name + NpcList(NpcIndex).flags.AttackedTime = GetTickCount Call SetNpcRef(UserList(UserIndex).flags.NPCAtacado, NpcIndex) End If End With diff --git a/Codigo/clsIniManager.cls b/Codigo/clsIniManager.cls index fd6025f9a..745bea04d 100644 --- a/Codigo/clsIniManager.cls +++ b/Codigo/clsIniManager.cls @@ -371,9 +371,10 @@ End Sub ' ' @param Main The name of the main section in which we will be searching. ' @param key The key of the value we are looking for. +' @param DefaultValue Default value if key is not found. ' @returns The value asociated with the given key under the requeted main section of the INI file or a null string if it's not found. -Public Function GetValue(ByVal Main As String, ByVal Key As String) +Public Function GetValue(ByVal Main As String, ByVal key As String, Optional ByVal DefaultValue As String = "") As String On Error GoTo GetValue_Err @@ -385,7 +386,6 @@ Public Function GetValue(ByVal Main As String, ByVal Key As String) '************************************************************** Dim i As Long Dim j As Long - Dim retval As String 'Search for the main node i = FindMain(UCase$(Main)) @@ -396,9 +396,11 @@ Public Function GetValue(ByVal Main As String, ByVal Key As String) j = FindKey(fileData(i), UCase$(Key)) 'If we found it we return it - If j >= 0 Then retval = fileData(i).values(j).Value - - GetValue = retval + If j >= 0 Then + GetValue = fileData(i).values(j).Value + Else + GetValue = DefaultValue + End If End If diff --git a/intervalos.ini b/intervalos.ini index 8929b6d06..4fc680fbe 100644 --- a/intervalos.ini +++ b/intervalos.ini @@ -17,6 +17,7 @@ IntervaloFrio=75 IntervaloWAVFX=190 IntervaloMover=200 IntervaloNpcAI=150 +IntervaloNpcOwner=10000 IntervaloTrabajarExtraer=3000 IntervaloTrabajarConstruir=500 IntervaloWS=180 'Cantidad de minutos