Aller au contenu
Top-Metin2.org - Vous êtes à la recherche d'un serveur Metin 2 ? ×
×
×
  • Créer...

Hystos

Membre
  • Compteur de contenus

    256
  • Inscription

  • Dernière visite

Messages posté(e)s par Hystos

  1. Salut.

     

    Pas besoin d'être expert en PHP pour te répondre, apache le fait déjà très bien :

     

    Warning: mysql_connect(): Access denied for user 'thomas280599'@'node12.cluster1.easy-hebergement.net' (using password: YES) in /public_html/thomastribout/index.php on line 14 

     

    Les identifiants de connexions rentrés dans index.php aux lignes 14/15 ne sont pas corrects. Vérifie particulièrement le mot de passe.

  2. Bonsoir,

     

    Merci du partage ! ;)

     

    Cependant, un oeil attentif repérera que ce n'est pas une nouvelle map mais bel et bien la map OX-Contest sans le "OX" au centre.

  3. Je te mets en spoiler la liste non exhaustive des bonus (et qui date... mais reste valide).

     

    Liste des bonus

    1    PV max

    2    PM max

    3    VIT

    4    INT

    5    STR

    6    DEX

    7    Vitesse d'attaque

    8    Vitesse de déplacement

    9    Vitesse du sort

    10    Régénération des HP

    11    Régénération EP

    12    Chance d'empoisoner

    13    Chance de provoquer un étourdissement

    14    Chance de ralentir

    15    Chance de faire une attaque critique

    16    Chance de coup percant

    17    Bonus contre les demi-humains

    18    Bonus contre les animaux

    19    Bonus contre les Orcs

    20    Bonus contre les mystiques

    21    Bonus contre les Mort-vivants

    22    Bonus contre le Mal

    23    Dommages absorbés par les PV

    24    Dommages absorbés par les PM

    25    Chance de prendre des PM aux ennemis  

    26    Chance de récupérer des PM lorsque vous touchez          

    27    Chance de bloquer un coup au Corps-à-corps

    28    Chance d'éviter les flèches

    29    Défensse à l'épée

    30    Défensse à l'épée à 2 mains

    31    Défensse à la dague

    32    Défensse au gong

    33    Défensse à l'éventail

    34    Résistance aux flèches

    35    Résistance au feu

    36    Résistance à la lumière

    37    Résistance à la magie

    38    Résistance au vent

    39    Chance de détourner une attaque au corps à corps

    40    Chance de détourner une malédiction

    41    Résistance contre le poison

    42    Chance de restaurer les PM

    43    Chance d'obtenir un bonus EXP

    44    Chance de drop le double de YANG

    45    Chance de drop le double d'objet

    46    Augmentation des effets de la potion

    47    Chance de réstaurer les PV

    48    Immunise contre l'étourdissement

    49    Immunise contre le ralentissement

    50    Immunise contre les chutes

     

    52    Portée de l'Arc

    53    Valeur d'attaque

    54    Défense

    55    Valeur d'attaque magique

    56    Défense magique

     

    58    Max endurance

    59    Bonus contre les Guerriers

    60    Bonus contre les Ninja

    61    Bonus contre les Sura

    62    Bonus contre les Shamans

    63    Bonus contre les monstres

    64    Valeur d'attaque (%)

    65    Défense (%)

    66    EXP (%)

    67    Chance de drop d'objet

    68    Chance de drop pour un Yang

     

     

    71    Dégats de compétences

    72    Dégats moyen

    73    Résistance contre les dégats de compétences

    74    Résistance moyenne au dégats

     

    76    Bonus CyberCafé EXP

    77    iCafé Chance de trouver des yangs

    78    Chance de parer une attaque Guerrier

    79    Chance de parer une attaque Ninja

    80    Chance de parer une attaque Sura

    81    Chance de parer une attaque Shaman

     

     

  4. Bien essayé valent76, sauf que ça ne satisfait pas au cahier des charges. Avec ton code, à chaque connexion, tu donneras l'objet en question au joueur et tu réinitialiseras le compteur. Ce n'est de toute évidence pas le but recherché. De plus, tu as fais des erreurs de syntaxes.

     

    Ayant trouvé ce problème intéressant, je vous propose un petit article sur des pistes de résolution.

     

    Dans toute la suite de ce message, je me baserai sur le fait que nous n'avons pas accès aux sources du jeu et que nos seuls outils sont les quêtes et la base de données.

    La première chose à faire, c'est de mettre en lumière les principaux obstacles qui s'opposent à nous.

    • Que se passe-t-il si le personnage possède plusieurs fois l'objet ?
    • Que se passe-t-il si le personnage jette l'objet ? Que se passe-t-il si le personnage vend l'objet ou l'échange ?

    Ensuite, on va essayer d'y répondre de la meilleure manière qui soit.

    Je ne traiterai ici que le premier obstacle majeur en supposant que le personnage peut posséder plusieurs fois l'objet dans son inventaire mais que ce dernier ne peut pas être échangé, jeté, vendu ou mis dans l'entrepôt de compte (chose possible via l'antiflag).

     

    Supposons que le personnage possède n fois l'objet (n supérieur à 1) dans son inventaire. 

    Posons objet_i , i allant de 1 à n, les n objets que le personnage possède dans son inventaire. Ils sont chacun identifiables par leur indice i (appartenant à l'intervalle d'entiers [|1, n|]).

     

    Première difficulté : comment savoir quel est l'objet utilisé ?

     

    En effet, on a l'habitude d'utiliser des syntaxes telles que ( when VNUM.use with ... begin ) qui permettent de capter l'événement d'utilisation d'un objet de vnum VNUM. Cependant, cela ne nous permet pas de savoir à quel objet on s'adresse. Comment individualiser notre objet ? En quoi est-il unique ?

    Il y a plusieurs choix de réponse possibles. Le plus logique, le plus habituel et le plus efficace : son identifiant unique. Chaque objet du jeu est en effet lié à un identifiant unique qui permet d'accéder à ses caractéristiques particulières. On le retrouve notamment comme clé primaire de la table item (base player). Il se trouve qu'on a facilement accès à cet identifiant via la fonction item.get_id() qui s'applique justement à un événement d'utilisation d'un objet. 

     

    Nous pouvons donc désormais identifier chacun des n objets présents dans l'inventaire grâce à son identifiant unique que nous noterons pour la suite objet_id_i, i allant de 1 à n

     

    Intéressons nous maintenant plus spécifiquement à un objet d'indice k, k appartenant à l'intervalle d'entiers [|1, n|].

     

    Deuxième difficulté : comment mettre en place la limite d'utilisation de cet objet ?

     

    Là encore, il y a de nombreuses techniques possibles.

    Fixons X le nombre de fois que l'objet peut être utilisé avant sa destruction.

     

    1ere solution : event_flag personnalisé

     

    Il nous faut un compteur, une variable numérique qui sera en quelque sorte liée à l'objet et que nous pourrons incrémenter ou décrémenter à souhait. Il se trouve que nous sommes capables de créer des variables numériques liées au personnage et de les gérer plutôt efficacement : les event flag. 

    Comment passer du personnage à l'objet ? Etant donné que par hypothèse l'objet ne changera pas de personnage, il est possible de transformer une variable du personnage en variable pour l'objet. On pourra choisir de nommer les variables liées à un objet avec un espace de nom réservé qui sera attribué dynamiquement en fonction de l'identifiant de l'objet. Nous sommes ainsi capables d'agir sur une variable numérique virtuellement liée à l'objet d'indice k.

     

    Exemple d'algorithme :

     

    Quand le personnage utilise l'objet k

            Si la valeur de la variable questflag "objet_" + objet_id_k + "_count" est strictement inférieure à X alors

                    On incrémente de 1 la valeur de la variable questflag "objet_" + objet_id_k + "_count"

            Sinon

                    On supprime la variable questflag "objet_" + objet_id_k + "_count" (un identifiant unique peut être réutilisé par un autre objet plus tard une fois l'objet détruit)

                    On supprime l'objet

            Fin si

            On téléporte le personnage

    Fin

     

    Avec cet algorithme, il n'y a rien à initialiser à l'obtention de l'objet. Tout se fait... tout seul. Il est redoutablement efficace et simple. Cependant, il ne pourra pas passer les obstacles suivants car l'objet ne serait alors plus lié au personnage.

     

    Bonus : réponse possible aux autres obstacles

     

     

    2eme solution : une technique plus énergivore à base de SQL

     

    Il est possible d'accéder aux bases de données du jeu dans une quête. Comme je l'ai déjà énoncé, chaque objet dans le jeu est en faite représenté par une entrée dans la table item (base player) dans laquelle on trouvera les informations particulières à cet objet (tandis que les informations globales à tous les objets du même vnum se situeront dans item_proto). Où peut-on créer une variable, "un endroit", où mettre notre compteur qui serait lié à l'objet ?

    Et bien la réponse paraît alors évidente : la table item, plus précisément dans l'entrée de l'objet étudié. 

    Nous avons plusieurs possibilités pour créer cette information : créer un nouveau champ ou utiliser un champ déjà existant.

    La première a l'avantage d'être plus propre et claire. Cependant, elle affectera tous les objets du jeu et doit donc être initialisée intelligemment pour ne pas créer d'incohérence. 

    La seconde est plus du "bidouillage" et pourtant c'est peut être celle que je préférerai dans ce cas. La raison est la suivante : il est possible suite à des circonstances qui dépassent cette intervention (exemple d'une amélioration) qu'un objet perde son identifiant unique et devienne un "nouvel objet", avec un nouvel identifiant. Il sera alors recréé à l'identique (excepté le vnum qui sera incrémenté dans le cas de l'amélioration) grâce à une duplication des valeurs connues par le jeu de l'objet (bonus, pierres) présentes dans la table item. Si on utilise un champ déjà existant, il sera alors lui aussi recopié et donc sauvegardé dans le nouvel objet. Dans l'autre cas, la valeur du nouveau champ ne sera pas recopié.

     

    Il nous faut donc choisir un champ déjà existant et non utilisé. Si le système s'adresse à un objet utilisable comme ici, je conseille d'utiliser une valeur de bonus (attrvalue) sans mettre d'attrtype. On aura alors aucun affichage graphique mais les données seront là. Dans le cas d'une arme ou d'une armure, on pensera à utiliser un des derniers socket.

     

    Nous utiliserons pour la suite le champ attrvalue0. La valeur inscrite dans item_proto (s'appliquant à tous les objets du même vnum) sera 0 (initialisation). Ensuite, on procède de la même manière que dans le précédent algorithme.

     

    Exemple d'algorithme :

     

     

    Quand le personnage utilise l'objet k

            On sélectionne avec une requête SQL la valeur de son attrvalue0 et on la stocke dans la variable count

            Si la valeur de la variable count est strictement inférieure à X alors

                    On incrémente de 1 la valeur de son attrvalue0 à l'aide d'une requête SQL

            Sinon

                    On supprime l'objet (le jeu se chargera de supprimer la ligne correspondante dans la table player)

            Fin si

            On téléporte le personnage

    Fin

     

    Le grand avantage de cette technique c'est qu'à priori elle triomphe de tous les obstacles que nous avons énumérés. 

    Cependant, je me dois de prévenir un éventuel utilisateur qu'il n'est pas conseillé d'utiliser des requêtes SQL dans les quêtes. Elles sont très énergivores, souvent peu efficaces (surtout dans une table aussi volumineuse que item) et pourront ralentir considérablement votre serveur.

     

    Comment choisir ?

     

    Cela dépend du besoin. Un anneau de téléportation à usage limité, je devine qu'il a sa place dans la boutique.

    Est-il nécessaire de laisser aux joueurs le droit de l'échanger, de le jeter, de le mettre dans son entrepôt ou de le vendre ? 

    Si oui, alors il est obligatoire d'utiliser la deuxième technique présentée. Heureusement, il n'y aura qu'une utilisation pour une téléportation, avec à chaque deux requêtes. C'est donc une charge tout à fait acceptable pour un serveur avec un minimum de moyens.

    Sinon, privilégiez la méthode avec les event flag qui est beaucoup plus efficace.

     

    Merci de votre lecture (et pardonnez moi si j'ai fais des erreurs...).

    • Love 1
  5. Oui, la dernière se fait également en SQL.

     

    Cependant, il peut être utile de l'agrémenter avec un langage quelconque pour écrire le moins de lignes possibles.

     

    En admettant que l'on souhaite donner les mêmes bonus à chaque classe, l'algorithme assez simple qui me vient en tête est le suivant :

     

    définir dans un tableau les armes et armures de chaque classe (les bonus donnés seront les mêmes. Dans le cas de bonus différents, il faudra également définir les bonus pour chaque item pour chaque classe dans un tableau).
    Pour chaque personnage créé précédemment (tu peux mettre des bornes d'id par exemple) faire
            donner un bijoux au personnage avec les bonus définis préalablement (requête SQL)
            idem pour les autres bijoux
            sélectionner la classe du personnage (peut être pris au début si on utilise une requête SQL)
            donner l'arme qui correspond à la classe du personnage au personnage avec les bonus définis préalablement (requête SQL)
            idem pour l'armure
    fin pour
    

     

    Pour les requêtes SQL à effectuer, tu peux te baser sur mon tutoriel (https://fr.metin2.dev/topic/12286-thread/).

  6. Niveau requis Débutant

    Temps estimé : 3 minutes

    Bonjour,

     

    Révélation

     

    Voici une fonction qui vous permettra de générer un mot de passe MySQL à la manière de PASSWORD().

    
    <?php
    	function mysqlPassword($raw){
    		return '*'.strtoupper(hash('sha1',pack('H*',hash('sha1', $raw))));
        }
    ?>

    Pour utiliser cette fonction, il vous suffit simplement d'appeler : mysqlPassword('votre mot de passe'); et elle vous retournera un mot de passe à la manière de la fonction PASSWORD() de MySQL.

     

     

    Cordialement,

    Hey hey

    • Love 1
  7. C'est à dire que ton cms est obsolète et que ta fait un énorme retour dans le passé en le choisissant...

     

    "mysql_connect(): The mysql extension is deprecated and will be removed in the future : use mysqli or PDO" est tout a fais normal sur wamp. Suffis juste de fermer skype, car Wamp a besoin du port 80 et comme j'ai pu voir que tu avais Skype qui lui utilise le port 80. Bonne soirée.

     

    Qu'est-ce qu'il faut pas lire !

     

    Cela vient simplement du fait que les fonctions du type mysql_ sont considérées comme archaïques. On te prévient d'ailleurs qu'elles risquent d'être supprimées dans une prochaine version de PHP. On te suggère de remplacer ces fonctions par mysqli_ ou PDO. 

     

    Tu peux choisir d'ignorer cet avertissement. Pour cela, tu peux directement modifier le niveau d'affichage des alertes dans ton fichier de configuration PHP. Sinon, tu peux faire ce qu'ils te proposent. La façon la plus simple est de passer en mysqli : tu as juste à rajouter un i derrière tous les mysql ;)

  8. En effet, le code

    local test = number(1,9)
       while test > 5 do // Tant que "test" est supérieur à 5 faire
           local test = number(1,9) // "test" reprend une valeur aléatoire entre 1 et 9
       end
       return test // retourne la valeur de test (supérieure à 5)
    

     

    fonctionnera mais est faux d'un point de vue algorithmique. Le second local n'est en rien nécessaire.

     

    Ce qu'il faut comprendre, c'est la portée de la variable test dans la boucle. Par exemple :

    function test()
        while condition do
             local texte = "chaine"
        end
        return texte
    end
    

     

     

    Ce code ne fonctionnera pas. La variable texte n'existe que dans la boucle et nul part ailleurs. Elle n'existe pas dans la fonction mère.

     

    Par contre,

    function test()
        local texte = "test"
        while condition do
             texte = "chaine"
        end
        return texte
    end
    

     

     

    nous renverra "chaine" (et non "test"). La variable texte est créée dans la fonction et sa valeur est modifiée dans la boucle.

     

    Il faut comprendre que si la variable est déclaré dans un élément parent, elle le sera dans un élément enfant.

    Si la variable déclarée dans l'élément parent est modifiée dans l'élément enfant, alors elle sera modifiée également dans l'élément parent.

     

    Attention : quand je parle de l'élément enfant, c'est uniquement une boucle ou une condition et JAMAIS un appel de fonction qui, si elle est déclarée dans un autre fichier, ne possède pas les variables de l'élément parent (d'où les arguments). Les arguments manipulés à l'intérieur de la fonction sont des copies des réels arguments situés dans l'élément "parent" (celui depuis lequel on a appelé la fonction) et donc ces derniers ne seront pas modifiés.

  9. En effet, comme l'a précisé Prindo, les timer partiront au prochain logout.

    Le meilleur moyen de faire une limite de temps pour un personnage est de rajouter un quest flag avec à l'intérieur un timestamp.

     

    De plus, je pense que la quête plantera au compilage. Tu n'as pas le droit d'écrire :

     

    if condition then
       //actions
    else condition2 then
       //actions
    end

     

     

    C'est absolument interdit. Soit tu mets juste "else" (= dans tous les autres cas), soit tu mets "elseif".

     

    On voit que tu es motivé. Pour améliorer ton code, je te propose plusieurs optiques :

    • Essaie de donner à tes variables de vrais noms compréhensibles pour qu'on voit tout de suite ce à quoi elles font références. En effet, tu t'es régulièrement planté de variables (exemple à la fin). Tel quel, ton code ne fonctionnera surement pas.
    • Rajouter un commentaire de temps en temps n'est pas une mauvaise chose (même si dans le cas d'une quête simple comme celle-ci ce n'est pas nécessaire).
    • Essaie d'optimiser au maximum ton code. A la place de faire 50 000 if / else, essaie de manipuler les données avec plus de doigté. A la base, l'informatique est fait pour les flemmards. Ton but : faire le maximum de chose avec le moins de lignes possibles et avec la plus grande modularité. Evidemment, c'est pas toujours évident mais dans ton cas, cela aurait pu être amélioré. Voici un petit exemple :
       
      - Code original (désolé pour l'indentation, c'est pas facile sur les forums en copié/collé)
                                local b3 = number(1,2)
                                if b3 == 1 then
                                     Say("La carte est bleue !")
                                     if pc.qetqf("bleu") == 1 then
                                         say("Vous avez remporté cette manche.")
                                         pc.give_item2(20003)
                                         pc.setqf("bleu_rouge", 2)
                                     elseif pc.qetqf("rouge") == 1 then
                                         say("Dommage, vous avez perdu cette manche.")
                                         pc.setqf("bleu_rouge", 2)
                                     end
                                 elseif b2 == 2 then
                                     if pc.qetqf("bleu") == 1 then
                                         say("Dommage, vous avez perdu cette manche.")
                                         pc.setqf("bleu_rouge", 2)
                                     elseif pc.qetqf("rouge") == 1 then
                                         say("Vous avez remporté cette manche.")
                                         pc.give_item2(20003)
                                         pc.setqf("bleu_rouge", 2)
                                     end
                                 end
      


       
      - et la correction

      //Le choix de ton utilisateur devrait être mis dans un quest flag choix, ayant pour valeur 1 ou 2 (bleu ou rouge), 
      ce qui réduira encore le nombre de lignes inutiles. On admettra ce fait pour la suite.
      local b3 = number(1,2)
      local couleurs_name = {"bleue", "rouge"}
      say("Le carte est "..couleurs_name[b3].." ! ")
      if b3 == pc.getqf("choix") then
           say("Vous avez remporté cette manche.")
           pc.give_item2(20003)
      else
           say("Dommage, vous avez perdu cette manche.")
      end
      pc.setqf("bleu_rouge", 2)                      
      


       
      Je divise par 2 le nombre de lignes utilisées pour la même chose, et rend le code beaucoup plus modulable. Par exemple, si tu veux changer le nom d'une couleur, c'est très rapide et facile à faire. Si tu veux en rajouter une aussi...

     

    Si tu as des questions, tu as mon Skype.

  10. Après avoir essayé pas mal d'offres, le mieux est de toi même héberger ton site sur un serveur dédié différent de celui sur lequel tourne le jeu.

     

    Tu pourras ainsi faire ce que tu veux avec (modifications apache, sécurités, mises à jour PHP). Après, c'est un peu plus cher...

Information importante

Conditions d’utilisation / Politique de confidentialité / Règles / Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.