-
-
Flux d'Activité
-
0
OldEraMT2 | Classique 2009 Oldschool | Niveau 99 | 7 langues | Sans pay2win | Bêta ouverte
Le serveur est ouvert aux joueurs de la bêta dès maintenant – télécharge, inscris-toi et commence à jouer aujourd’hui. Chaque nouveau membre nous fait plaisir ! "> OldEraMT2 – classique 2009 sans pay2win · bêta-testeurs et équipe recherchés NIVEAU 99 · 4 CLASSES · 3 ROYAUMES · 7 LANGUES Présentation bêta – Ceci est la présentation de la bêta. La grande présentation suivra après des tests bêta approfondis – avec tout ce que vous nous aurez remonté d’ici là. Présentation · Équipement · Téléchargement · Discord · Inscription Par SA_Dev_Null, l’administrateur — Pourquoi OldEra existe. Il y a une quinzaine d’années, mon premier serveur Metin2 tournait dans une chambre d’enfant – via Hamachi, pour une poignée d’amis. Depuis, j’ai joué à Metin2 pendant des années, sur de grands et de petits serveurs, et j’ai toujours vu la même chose : à un moment, c’est le portefeuille qui décide, pas le temps de jeu. Le rêve est resté : un serveur qui se sent comme en 2009, sans pay2win – et que je ne conçois pas seul à un bureau, mais avec les gens qui y jouent. Ce qui est bon reste. Ce qui coince change. Ouvertement et de façon traçable. Ces derniers mois, c’est devenu OldEra : serveur, client, launcher, un wiki dans le jeu, le Hub, un marché des joueurs qui fonctionne aussi hors ligne et une bêta en sept langues. Beaucoup est fini, certaines choses restent brutes. C’est exactement à ça que sert la bêta. Si tu connais Metin2 et que tu veux dire honnêtement ce qui sonne juste et ce qui ne l’est pas – tu es au bon endroit. Et si tu veux plus que tester : nous cherchons des gens pour l’équipe. Tests, communauté, traductions, quêtes, client ou design. L’épreuve de courage – à mains nues. Tout le monde commence pareil : cinq chiens sauvages, sans arme. Tant que tu combats sans arme, tes poings frappent très fort. Ensuite tu reçois l’équipement de départ de ta classe. » Voir en interactif (avec les infobulles du jeu) Aucune arme n’est pareille. Épée de pleine lune, Épée empoisonnée et compagnie fonctionnent comme avant : chacune reçoit au drop son propre jet de dégâts moyens (DM) et dégâts de compétence (DC). Plus de DM signifie moins de DC – et inversement. Lance toi-même : la même formule que sur le serveur. Exemple sur l’image : 30 % DM / −12 % DC Ce vers quoi tu travailles. Les armes dont tout le monde parle – et comment les obtenir. Coûts, chances et matériaux viennent directement des tables du jeu. Une arme de niveau 65 en +9 ? Le forgeron la transforme en arme de niveau 80 – 100 % de réussite, avec des parchemins de bénédiction et un traité d’escrime. Dès le niveau 75, la Faucheuse t’attend au 9e étage de la Tour des Démons. Son coffre contient les armes de niveau 70 de toutes les classes – avec la vraie chance de chacune. » Voir en interactif (avec les infobulles du jeu) Des petites choses qui changent tout. Ce qui rend le quotidien dans OldEra plus agréable – en vraies fenêtres du jeu. » Voir en interactif (avec les infobulles du jeu) Ce qui existe déjà Un wiki dans le jeu avec les sources des objets et un guide pour ta prochaine étape Le Hub : recherche, commerce, wiki, classements et liste de souhaits dans un seul menu Un marché des joueurs qui continue hors ligne – avec courrier commercial Messager avec amis, discussions de groupe, courrier et tickets directs à l’équipe Chaque arme et armure avec les vraies valeurs sur le site – infobulle comme dans le jeu Pas de pay2win – les paiements en argent réel sont désactivés dans la bêta Classique 2009 : niveau 1–99, trois royaumes, quatre classes Les changements se font avec la communauté Sept langues, téléchargement sans mot de passe Qui nous cherchons Des bêta-testeurs qui disent honnêtement ce qui sonne juste et ce qui ne l’est pas. Et des gens pour l’équipe : tests, communauté, traductions, quêtes, client ou design. Dis-nous en quelques mots ce que tu veux faire, quelles langues tu parles et combien de temps tu as à peu près. Bêta ouverte depuis le 23.09.2026, pas encore de date de lancement officielle. Téléchargement et inscription ouverts. Chaque image est une vraie fenêtre du jeu – générée directement depuis le client, sans montage. Elles se mettent à jour à chaque patch. Présentation · Équipement · Téléchargement · Discord · Inscription -
-
6
problème de connexion à mon serveur local (je suis débutant dans ce genre d'entreprise )
Salut, si ton serveur démarre correctement mais que ton client reste sur « erreur lors de la connexion au serveur », je regarderais d’abord la partie IP/ports. Si ton serveur tourne dans une VM, vérifie que l’IP renseignée dans ton serverinfo.py correspond bien à l’IP de la VM et pas forcément à 127.0.0.1. Vérifie aussi que les ports indiqués côté client correspondent bien à ceux de tes CONFIG (auth + channels). Regarde également les syserr/syslog du serveur au moment où tu essayes de te connecter, ainsi que le syserr du client, ça permettra de voir si la connexion arrive jusqu’au serveur ou non. Si tu peux, poste ton serverinfo.py, les ports de tes CONFIG et les dernières lignes du syserr après une tentative de connexion. On pourra sûrement repérer rapidement ce qui bloque. -
2
problème de lancement serveur
Salut, d’après ta capture les connexions MySQL ont l’air de fonctionner : PLAYER, ACCOUNT, COMMON et HOTBACKUP passent en Success. Donc à première vue ce n’est pas ton IP qui empêche les channels de démarrer. Le process semble plutôt s’arrêter juste après, au moment du chargement des protos, puisqu’on voit item_proto_test.txt juste avant le retour au shell. Regarde surtout le fichier syserr du channel qui ne démarre pas, par exemple dans le dossier channel1/core1 ou équivalent, et poste les dernières lignes. Vérifie aussi que item_proto_test.txt est bien présent, au bon emplacement et compatible avec tes sources/files 2016. Si les files et les sources ne correspondent pas exactement, une différence dans le format de l’item_proto peut aussi faire fermer le game au démarrage. Envoie le syserr, ce sera beaucoup plus simple pour identifier l’erreur exacte. -
26
Metin2 40250 / 2014 Serverfiles + Client + SRC [ 15 Langues ]
Merci beaucoup pour les files -
9
-
0
[PVM/PVP] ATLAX2 - EASY PLAY
ATLAX L’ESSENCE CLASSIQUE DE METIN2, PRÉPARÉE POUR UNE NOUVELLE GÉNÉRATION. NIVEAU 120 • CHAMPION 30 • YOHARA INTERNATIONAL • SANS PAY-TO-WIN ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SERVEUR EN LIGNE Ouvert officiellement depuis le 31 juillet 2026 SITE WEB https://atlax2.com/ PRÉSENTATION COMPLÈTE https://welcome.atlax2.com/ DISCORD https://discord.com/invite/rd62BJC6Yj ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BIENVENUE SUR ATLAX ATLAX a été conçu pour offrir une expérience Metin2 équilibrée, authentique et durable, inspirée de l’essence classique du jeu tout en profitant des améliorations modernes. Que vous soyez un ancien joueur de Metin2 ou que vous recherchiez simplement une nouvelle aventure à long terme, ATLAX vous propose une progression basée sur votre activité, votre connaissance du jeu et votre investissement. Aucun Pay-to-Win. Commencez votre aventure au niveau 1, progressez jusqu’au niveau 120, débloquez le Champion 30 et découvrez les terres de Yohara. De nouveaux systèmes, des défis élémentaires, la Volonté Sung Ma et un véritable contenu end-game vous attendent. GUERRIER • NINJA • SURA • CHAMANE • LYCAN ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SERVEUR INTERNATIONAL ATLAX accueille des joueurs du monde entier. Português • English • Français • Español Deutsch • Italiano • Türkçe ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ COMMENCEZ VOTRE AVENTURE Chaque joueur commence avec un équipement équilibré permettant de rendre le début du jeu plus agréable sans supprimer le plaisir de la progression. ÉQUIPEMENT DE DÉPART • Arme niveau 1 +9 • Armure, accessoires et chaussures +9 • Cheval armé — Niveau 11 • Monture de départ • Familier de départ • Costume et coiffure temporaires • Coffre d’apprenti • Langues en M1 • Appel du cheval au niveau 10 PROGRESSION DÉBUTANT AMÉLIORÉE • Armes gratuites tous les 10 niveaux jusqu’au niveau 70 • Missions de chasse améliorées • Objectifs plus clairs • Meilleures récompenses • Progression plus fluide • Moins d’attente inutile ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PROGRESSION & SYSTÈMES MISSIONS DU BIOLOGISTE Les missions du Biologiste vous accompagnent du niveau 30 jusqu’au Champion 30. Elles permettent d’obtenir des bonus permanents importants : • Valeur d’attaque et Défense • PV maximum • Dégâts et Résistance contre les Boss • Force contre les pierres Metin • Dégâts de compétence • Dégâts moyens • Résistance contre toutes les classes • Puissance élémentaire • Valeurs de Volonté Sung Ma SYSTÈMES PRINCIPAUX • Progression du cheval jusqu’au niveau 40 • 6e et 7e bonus • Alchimie des Pierres-Dragon améliorée • Raffinage automatique • Talismans et puissance élémentaire • Système de titres • Effets de set permanents • Reliques d’âme • Familiers évolutifs • Système Aura • Écharpes d’épaule • Pierres spirituelles pour chaussures • World Boss toutes les 8 heures ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CONFORT DE JEU ATLAX conserve l’identité de Metin2 tout en réduisant les tâches répétitives grâce à plusieurs fonctionnalités modernes. • Inventaire avancé divisé par catégories • Barre de compétences étendue • Auto-Chasse configurable • Filtre de butin • Système de courrier • Recherche de boutiques intégrée • Map de commerce réorganisée • Aperçu des coffres • Ouverture multiple de coffres • Vente rapide de plusieurs objets • Démantèlement rapide d’équipement • Anti-EXP • Informations détaillées des donjons • Aperçu direct des drops • Wiki intégré • Aperçu 3D des costumes, familiers et montures • Taille du texte ajustable • Code PIN de sécurité RACCOURCIS F8 — Biologiste F9 — Wiki K — Auto-Chasse P — Familier ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MAPS & EXPLORATION Votre aventure commence dans les terres classiques de Metin2 avant de vous conduire vers des régions beaucoup plus dangereuses. ANCIEN CONTINENT Seungryong Valley • Temple Hwang • Mont Sohan Désert Yongbi • Doyyumhwan • Forêt Fantôme Forêt Rouge • Grottes des Araignées • Grotte de l’Exil NIVEAUX 90 — 120 Cape Dragon Fire • Baie de Nephrite Montagnes du Tonnerre • Falaise Gautama Temple Ochao • Forêt Enchantée MONDE ÉLÉMENTAIRE Domaine Élémentaire de la Foudre Domaine Élémentaire du Feu Domaine Élémentaire des Ténèbres Plateau des Forces Anciennes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ YOHARA Atteindre le système Champion ouvre un tout nouveau chapitre de votre aventure. Explorez Yohara, développez votre Volonté Sung Ma et préparez-vous à affronter certains des contenus les plus avancés d’ATLAX. • Forteresse Abandonnée • Plaine de Dong Gwang • Terres Désolées de Seo Gwang • Gouffre de Nam Gwang • Passage de Yilad • Ravin du Vent du Nord • Gorge des Âmes • Temple du Serpent De nouvelles maps et de nouveaux contenus Yohara continueront d’être ajoutés au fur et à mesure de l’évolution d’ATLAX. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DONJONS ZODIAQUE Niveau 20+ TOUR DES DÉMONS Niveau 40+ ANTRE DE LA BARONNE ARAIGNÉE Niveau 50+ CATACOMBES DU DIABLE Niveau 75+ DRAGON BERAN-SETAOU Niveau 75+ REPAIRE DE MELEY Niveau 75+ / 90+ DÉFENSE DU NAVIRE Niveau 90+ EREBUS Niveau 95+ FORTERESSE DU DRAGON ROUGE Niveau 100+ TOUR DE NEMERE Niveau 100+ PLATEAU DE L’ILLUSION Niveau 110+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FAILLES TEMPORELLES & ÉVEIL À partir du niveau 110, des défis familiers reviennent dans des versions plus difficiles avec des ennemis renforcés et des récompenses avancées. DONJONS DE YOHARA • Tour Sung Mahi • Profondeurs du Vent du Nord • Temple du Serpent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CONTENU DE GUILDE Rassemblez les membres de votre guilde et entrez dans le PALAIS DU ROI DRAGON À mesure que votre guilde progresse, de nouveaux Boss deviennent disponibles. AKZADUR Guilde Niveau 21+ NAFAROTH Guilde Niveau 24+ EXEDYAR Guilde Niveau 27+ RUILITH Guilde Niveau 30+ TYOLDURAN Guilde Niveau 35+ Préparation, coordination et maîtrise des puissances élémentaires seront indispensables. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ÉVÉNEMENTS & ACTIVITÉS AU MOINS UN ÉVÉNEMENT ACTIF CHAQUE JOUR • World Boss • Jeu de cartes Okey • Attrapez le Roi • Yut Nori • Trio de Monstres • Duel du Voyant • Rituel du Sang • Puzzle de Pêche • Flower Power • Boss Reaper • Chasse au Trésor • Fièvre des Metins • Otherworld • Événements de Noël • Événements de Pâques • Événements du Ramadan • Tournois PvP • Événements communautaires Tous les événements programmés sont visibles directement dans le Calendrier d’Événements en jeu. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ UN SERVEUR CONSTRUIT AVEC SA COMMUNAUTÉ ATLAX est conçu comme un projet à long terme. De nouveaux contenus, systèmes, événements et améliorations seront régulièrement ajoutés. Des sondages seront également organisés afin que les suggestions et les retours de la communauté participent réellement à l’évolution du serveur. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ÊTES-VOUS PRÊT À COMMENCER ? ATLAX EST EN LIGNE SITE WEB https://atlax2.com/ PRÉSENTATION https://welcome.atlax2.com/ REJOINDRE LE DISCORD https://discord.com/invite/rd62BJC6Yj ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ATLAX LA LÉGENDE COMMENCE AVEC VOUS. -
2
problème de lancement serveur
Wow ! Tu déterres des reliques qui devraient rester enfouis ! Sinon, quand tu est rendu a l'étape comme sur ton screenshot, si tu fais la commande ps est ce que le serveur est lancé ? L'ip que tu dois configurer dans ton fichier serverinfo.py c'est l'ip de ta machine que tu peux avoir en utilisant la commande ifconfig -
6
problème de connexion à mon serveur local (je suis débutant dans ce genre d'entreprise )
Bonjour j'ai le même soucis je n'arrive pas a le réglé
-

Question
CHAPPiE 6
Bonsoir,
depuis 17 heures je m'acharne sur un fichier "sectree_manager.cpp", je ne trouve pas la solution à mon problème,
j'ai pourtant suivi le tutoriel comme il se devait!
Si quelqu'un pouvait le faire à ma place, ça fait 10 fois que je recommence sans cesse...
Voici le fichier d'origine:
#include "stdafx.h" #include #include "../../libgame/include/targa.h" #include "../../libgame/include/attribute.h" #include "config.h" #include "utils.h" #include "sectree_manager.h" #include "regen.h" #include "lzo_manager.h" #include "desc.h" #include "desc_manager.h" #include "char.h" #include "char_manager.h" #include "item.h" #include "item_manager.h" #include "buffer_manager.h" #include "packet.h" #include "start_position.h" #include "dev_log.h" WORD SECTREE_MANAGER::current_sectree_version = MAKEWORD(0, 3); SECTREE_MAP::SECTREE_MAP() { memset( &m_setting, 0, sizeof(m_setting) ); } SECTREE_MAP::~SECTREE_MAP() { MapType::iterator it = map_.begin(); while (it != map_.end()) { LPSECTREE sectree = (it++)->second; M2_DELETE(sectree); } map_.clear(); } SECTREE_MAP::SECTREE_MAP(SECTREE_MAP & r) { m_setting = r.m_setting; MapType::iterator it = r.map_.begin(); while (it != r.map_.end()) { LPSECTREE tree = M2_NEW SECTREE; tree->m_id.coord = it->second->m_id.coord; tree->CloneAttribute(it->second); map_.insert(MapType::value_type(it->first, tree)); ++it; } Build(); } LPSECTREE SECTREE_MAP::Find(DWORD dwPackage) { MapType::iterator it = map_.find(dwPackage); if (it == map_.end()) return NULL; return it->second; } LPSECTREE SECTREE_MAP::Find(DWORD x, DWORD y) { SECTREEID id; id.coord.x = x / SECTREE_SIZE; id.coord.y = y / SECTREE_SIZE; return Find(id.package); } void SECTREE_MAP::Build() { // Ŭ¶óÀÌ¾ðÆ®¿¡°Ô ¹Ý°æ 150m ij¸¯ÅÍÀÇ Á¤º¸¸¦ ÁÖ±âÀ§ÇØ // 3x3Ä -> 5x5 ÄÀ¸·Î ÁÖº¯sectree È®´ë(Çѱ¹) if (LC_IsYMIR() || LC_IsKorea()) { #define NEIGHBOR_LENGTH 5 #define NUM_OF_NEIGHBORS (NEIGHBOR_LENGTH * NEIGHBOR_LENGTH - 1) int width = NEIGHBOR_LENGTH / 2; struct neighbor_coord_s { int x; int y; } neighbor_coord[NUM_OF_NEIGHBORS]; { int i = 0; for (int x = -width; x <= width; ++x) { for (int y = -width; y <= width; ++y) { if (x == 0 && y == 0) continue; neighbor_coord[i].x = x * SECTREE_SIZE; neighbor_coord[i].y = y * SECTREE_SIZE; ++i; } } } // // ¸ðµç sectree¿¡ ´ëÇØ ÁÖÀ§ sectreeµé ¸®½ºÆ®¸¦ ¸¸µç´Ù. // MapType::iterator it = map_.begin(); while (it != map_.end()) { LPSECTREE tree = it->second; tree->m_neighbor_list.push_back(tree); // ÀÚ½ÅÀ» ³Ö´Â´Ù. sys_log(3, "%dx%d", tree->m_id.coord.x, tree->m_id.coord.y); int x = tree->m_id.coord.x * SECTREE_SIZE; int y = tree->m_id.coord.y * SECTREE_SIZE; for (DWORD i = 0; i < NUM_OF_NEIGHBORS; ++i) { LPSECTREE tree2 = Find(x + neighbor_coord[i].x, y + neighbor_coord[i].y); if (tree2) { sys_log(3, " %d %dx%d", i, tree2->m_id.coord.x, tree2->m_id.coord.y); tree->m_neighbor_list.push_back(tree2); } } ++it; } } else { struct neighbor_coord_s { int x; int y; } neighbor_coord[8] = { { -SECTREE_SIZE, 0 }, { SECTREE_SIZE, 0 }, { 0 , -SECTREE_SIZE }, { 0 , SECTREE_SIZE }, { -SECTREE_SIZE, SECTREE_SIZE }, { SECTREE_SIZE, -SECTREE_SIZE }, { -SECTREE_SIZE, -SECTREE_SIZE }, { SECTREE_SIZE, SECTREE_SIZE }, }; // // ¸ðµç sectree¿¡ ´ëÇØ ÁÖÀ§ sectreeµé ¸®½ºÆ®¸¦ ¸¸µç´Ù. // MapType::iterator it = map_.begin(); while (it != map_.end()) { LPSECTREE tree = it->second; tree->m_neighbor_list.push_back(tree); // ÀÚ½ÅÀ» ³Ö´Â´Ù. sys_log(3, "%dx%d", tree->m_id.coord.x, tree->m_id.coord.y); int x = tree->m_id.coord.x * SECTREE_SIZE; int y = tree->m_id.coord.y * SECTREE_SIZE; for (DWORD i = 0; i < 8; ++i) { LPSECTREE tree2 = Find(x + neighbor_coord[i].x, y + neighbor_coord[i].y); if (tree2) { sys_log(3, " %d %dx%d", i, tree2->m_id.coord.x, tree2->m_id.coord.y); tree->m_neighbor_list.push_back(tree2); } } ++it; } } } SECTREE_MANAGER::SECTREE_MANAGER() { } SECTREE_MANAGER::~SECTREE_MANAGER() { /* std::map::iterator it = m_map_pkSectree.begin(); while (it != m_map_pkSectree.end()) { M2_DELETE(it->second); ++it; } */ } LPSECTREE_MAP SECTREE_MANAGER::GetMap(long lMapIndex) { std::map::iterator it = m_map_pkSectree.find(lMapIndex); if (it == m_map_pkSectree.end()) return NULL; return it->second; } LPSECTREE SECTREE_MANAGER::Get(DWORD dwIndex, DWORD package) { LPSECTREE_MAP pkSectreeMap = GetMap(dwIndex); if (!pkSectreeMap) return NULL; return pkSectreeMap->Find(package); } LPSECTREE SECTREE_MANAGER::Get(DWORD dwIndex, DWORD x, DWORD y) { SECTREEID id; id.coord.x = x / SECTREE_SIZE; id.coord.y = y / SECTREE_SIZE; return Get(dwIndex, id.package); } // ----------------------------------------------------------------------------- // Setting.txt ·Î ºÎÅÍ SECTREE ¸¸µé±â // ----------------------------------------------------------------------------- int SECTREE_MANAGER::LoadSettingFile(long lMapIndex, const char * c_pszSettingFileName, TMapSetting & r_setting) { memset(&r_setting, 0, sizeof(TMapSetting)); FILE * fp = fopen(c_pszSettingFileName, "r"); if (!fp) { sys_err("cannot open file: %s", c_pszSettingFileName); return 0; } char buf[256], cmd[256]; int iWidth = 0, iHeight = 0; while (fgets(buf, 256, fp)) { sscanf(buf, " %s ", cmd); if (!strcasecmp(cmd, "MapSize")) { sscanf(buf, " %s %d %d ", cmd, &iWidth, &iHeight); } else if (!strcasecmp(cmd, "BasePosition")) { sscanf(buf, " %s %d %d", cmd, &r_setting.iBaseX, &r_setting.iBaseY); } else if (!strcasecmp(cmd, "CellScale")) { sscanf(buf, " %s %d ", cmd, &r_setting.iCellScale); } } fclose(fp); if ((iWidth == 0 && iHeight == 0) || r_setting.iCellScale == 0) { sys_err("Invalid Settings file: %s", c_pszSettingFileName); return 0; } r_setting.iIndex = lMapIndex; r_setting.iWidth = (r_setting.iCellScale * 128 * iWidth); r_setting.iHeight = (r_setting.iCellScale * 128 * iHeight); return 1; } LPSECTREE_MAP SECTREE_MANAGER::BuildSectreeFromSetting(TMapSetting & r_setting) { LPSECTREE_MAP pkMapSectree = M2_NEW SECTREE_MAP; pkMapSectree->m_setting = r_setting; int x, y; LPSECTREE tree; for (x = r_setting.iBaseX; x < r_setting.iBaseX + r_setting.iWidth; x += SECTREE_SIZE) { for (y = r_setting.iBaseY; y < r_setting.iBaseY + r_setting.iHeight; y += SECTREE_SIZE) { tree = M2_NEW SECTREE; tree->m_id.coord.x = x / SECTREE_SIZE; tree->m_id.coord.y = y / SECTREE_SIZE; pkMapSectree->Add(tree->m_id.package, tree); sys_log(3, "new sectree %d x %d", tree->m_id.coord.x, tree->m_id.coord.y); } } if ((r_setting.iBaseX + r_setting.iWidth) % SECTREE_SIZE) { tree = M2_NEW SECTREE; tree->m_id.coord.x = ((r_setting.iBaseX + r_setting.iWidth) / SECTREE_SIZE) + 1; tree->m_id.coord.y = ((r_setting.iBaseY + r_setting.iHeight) / SECTREE_SIZE); pkMapSectree->Add(tree->m_id.package, tree); } if ((r_setting.iBaseY + r_setting.iHeight) % SECTREE_SIZE) { tree = M2_NEW SECTREE; tree->m_id.coord.x = ((r_setting.iBaseX + r_setting.iWidth) / SECTREE_SIZE); tree->m_id.coord.y = ((r_setting.iBaseX + r_setting.iHeight) / SECTREE_SIZE) + 1; pkMapSectree->Add(tree->m_id.package, tree); } return pkMapSectree; } void SECTREE_MANAGER::LoadDungeon(int iIndex, const char * c_pszFileName) { FILE* fp = fopen(c_pszFileName, "r"); if (!fp) return; int count = 0; // for debug while (!feof(fp)) { char buf[1024]; if (NULL == fgets(buf, 1024, fp)) break; if (buf[0] == '#' || buf[0] == '/' && buf[1] == '/') continue; std::istringstream ins(buf, std::ios_base::in); std::string position_name; int x, y, sx, sy, dir; ins >> position_name >> x >> y >> sx >> sy >> dir; if (ins.fail()) continue; x -= sx; y -= sy; sx *= 2; sy *= 2; sx += x; sy += y; m_map_pkArea[iIndex].insert(std::make_pair(position_name, TAreaInfo(x, y, sx, sy, dir))); count++; } fclose(fp); sys_log(0, "Dungeon Position Load [%3d]%s count %d", iIndex, c_pszFileName, count); } // Fix me // ÇöÀç Town.txt¿¡¼ x, y¸¦ ±×³É ¹Þ°í, ±×°É ÀÌ ÄÚµå ³»¿¡¼ base ÁÂÇ¥¸¦ ´õÇØÁֱ⠶§¹®¿¡ // ´Ù¸¥ ¸Ê¿¡ Àִ Ÿ¿îÀ¸·Î Àý´ë À̵¿ÇÒ ¼ö ¾ø°Ô µÇ¾îÀÖ´Ù. // ¾Õ¿¡ mapÀ̶ó°Å³ª, ±âŸ ´Ù¸¥ ½Äº°ÀÚ°¡ ÀÖÀ¸¸é, // ´Ù¸¥ ¸ÊÀÇ Å¸¿îÀ¸·Îµµ À̵¿ÇÒ ¼ö ÀÖ°Ô ÇÏÀÚ. // by rtsummit bool SECTREE_MANAGER::LoadMapRegion(const char * c_pszFileName, TMapSetting & r_setting, const char * c_pszMapName) { FILE * fp = fopen(c_pszFileName, "r"); if ( test_server ) sys_log( 0, "[LoadMapRegion] file(%s)", c_pszFileName ); if (!fp) return false; int iX=0, iY=0; PIXEL_POSITION pos[3] = { {0,0,0}, {0,0,0}, {0,0,0} }; fscanf(fp, " %d %d ", &iX, &iY); int iEmpirePositionCount = fscanf(fp, " %d %d %d %d %d %d ", &pos[0].x, &pos[0].y, &pos[1].x, &pos[1].y, &pos[2].x, &pos[2].y); fclose(fp); if( iEmpirePositionCount == 6 ) { for ( int n = 0; n < 3; ++n ) sys_log( 0 ,"LoadMapRegion %d %d ", pos[n].x, pos[n].y ); } else { sys_log( 0, "LoadMapRegion no empire specific start point" ); } TMapRegion region; region.index = r_setting.iIndex; region.sx = r_setting.iBaseX; region.sy = r_setting.iBaseY; region.ex = r_setting.iBaseX + r_setting.iWidth; region.ey = r_setting.iBaseY + r_setting.iHeight; region.strMapName = c_pszMapName; region.posSpawn.x = r_setting.iBaseX + (iX * 100); region.posSpawn.y = r_setting.iBaseY + (iY * 100); r_setting.posSpawn = region.posSpawn; sys_log(0, "LoadMapRegion %d x %d ~ %d y %d ~ %d, town %d %d", region.index, region.sx, region.ex, region.sy, region.ey, region.posSpawn.x, region.posSpawn.y); if (iEmpirePositionCount == 6) { region.bEmpireSpawnDifferent = true; for (int i = 0; i < 3; i++) { region.posEmpire[i].x = r_setting.iBaseX + (pos[i].x * 100); region.posEmpire[i].y = r_setting.iBaseY + (pos[i].y * 100); } } else { region.bEmpireSpawnDifferent = false; } m_vec_mapRegion.push_back(region); sys_log(0,"LoadMapRegion %d End", region.index); return true; } bool SECTREE_MANAGER::LoadAttribute(LPSECTREE_MAP pkMapSectree, const char * c_pszFileName, TMapSetting & r_setting) { FILE * fp = fopen(c_pszFileName, "rb"); if (!fp) { sys_err("SECTREE_MANAGER::LoadAttribute : cannot open %s", c_pszFileName); return false; } int iWidth, iHeight; fread(&iWidth, sizeof(int), 1, fp); fread(&iHeight, sizeof(int), 1, fp); int maxMemSize = LZOManager::instance().GetMaxCompressedSize(sizeof(DWORD) * (SECTREE_SIZE / CELL_SIZE) * (SECTREE_SIZE / CELL_SIZE)); unsigned int uiSize; unsigned int uiDestSize; #ifndef _MSC_VER BYTE abComp[maxMemSize]; #else BYTE* abComp = M2_NEW BYTE[maxMemSize]; #endif DWORD * attr = M2_NEW DWORD[maxMemSize]; for (int y = 0; y < iHeight; ++y) for (int x = 0; x < iWidth; ++x) { // UNION À¸·Î ÁÂÇ¥¸¦ ÇÕÃĸ¸µç DWORD°ªÀ» ¾ÆÀ̵ð·Î »ç¿ëÇÑ´Ù. SECTREEID id; id.coord.x = (r_setting.iBaseX / SECTREE_SIZE) + x; id.coord.y = (r_setting.iBaseY / SECTREE_SIZE) + y; LPSECTREE tree = pkMapSectree->Find(id.package); // SERVER_ATTR_LOAD_ERROR if (tree == NULL) { sys_err("FATAL ERROR! LoadAttribute(%s) - cannot find sectree(package=%x, coord=(%u, %u), map_index=%u, map_base=(%u, %u))", c_pszFileName, id.package, id.coord.x, id.coord.y, r_setting.iIndex, r_setting.iBaseX, r_setting.iBaseY); sys_err("ERROR_ATTR_POS(%d, %d) attr_size(%d, %d)", x, y, iWidth, iHeight); sys_err("CHECK! 'Setting.txt' and 'server_attr' MAP_SIZE!!"); pkMapSectree->DumpAllToSysErr(); abort(); M2_DELETE_ARRAY(attr); #ifdef _MSC_VER M2_DELETE_ARRAY(abComp); #endif return false; } // END_OF_SERVER_ATTR_LOAD_ERROR if (tree->m_id.package != id.package) { sys_err("returned tree id mismatch! return %u, request %u", tree->m_id.package, id.package); fclose(fp); M2_DELETE_ARRAY(attr); #ifdef _MSC_VER M2_DELETE_ARRAY(abComp); #endif return false; } fread(&uiSize, sizeof(int), 1, fp); fread(abComp, sizeof(char), uiSize, fp); //LZOManager::instance().Decompress(abComp, uiSize, (BYTE *) tree->GetAttributePointer(), &uiDestSize); uiDestSize = sizeof(DWORD) * maxMemSize; LZOManager::instance().Decompress(abComp, uiSize, (BYTE *) attr, &uiDestSize); if (uiDestSize != sizeof(DWORD) * (SECTREE_SIZE / CELL_SIZE) * (SECTREE_SIZE / CELL_SIZE)) { sys_err("SECTREE_MANAGER::LoadAttribte : %s : %d %d size mismatch! %d", c_pszFileName, tree->m_id.coord.x, tree->m_id.coord.y, uiDestSize); fclose(fp); M2_DELETE_ARRAY(attr); #ifdef _MSC_VER M2_DELETE_ARRAY(abComp); #endif return false; } tree->BindAttribute(M2_NEW CAttribute(attr, SECTREE_SIZE / CELL_SIZE, SECTREE_SIZE / CELL_SIZE)); } fclose(fp); M2_DELETE_ARRAY(attr); #ifdef _MSC_VER M2_DELETE_ARRAY(abComp); #endif return true; } bool SECTREE_MANAGER::GetRecallPositionByEmpire(int iMapIndex, BYTE bEmpire, PIXEL_POSITION & r_pos) { std::vector::iterator it = m_vec_mapRegion.begin(); // 10000À» ³Ñ´Â ¸ÊÀº ÀνºÅϽº ´øÀü¿¡¸¸ ÇÑÁ¤µÇ¾îÀÖ´Ù. if (iMapIndex >= 10000) { iMapIndex /= 10000; } while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (rRegion.index == iMapIndex) { if (rRegion.bEmpireSpawnDifferent && bEmpire >= 1 && bEmpire <= 3) r_pos = rRegion.posEmpire[bEmpire - 1]; else r_pos = rRegion.posSpawn; return true; } } return false; } bool SECTREE_MANAGER::GetCenterPositionOfMap(long lMapIndex, PIXEL_POSITION & r_pos) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (rRegion.index == lMapIndex) { r_pos.x = rRegion.sx + (rRegion.ex - rRegion.sx) / 2; r_pos.y = rRegion.sy + (rRegion.ey - rRegion.sy) / 2; r_pos.z = 0; return true; } } return false; } bool SECTREE_MANAGER::GetSpawnPositionByMapIndex(long lMapIndex, PIXEL_POSITION& r_pos) { if (lMapIndex> 10000) lMapIndex /= 10000; std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (lMapIndex == rRegion.index) { r_pos = rRegion.posSpawn; return true; } } return false; } bool SECTREE_MANAGER::GetSpawnPosition(long x, long y, PIXEL_POSITION & r_pos) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (x >= rRegion.sx && y >= rRegion.sy && x < rRegion.ex && y < rRegion.ey) { r_pos = rRegion.posSpawn; return true; } } return false; } bool SECTREE_MANAGER::GetMapBasePositionByMapIndex(long lMapIndex, PIXEL_POSITION & r_pos) { if (lMapIndex> 10000) lMapIndex /= 10000; std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); //if (x >= rRegion.sx && y >= rRegion.sy && x < rRegion.ex && y < rRegion.ey) if (lMapIndex == rRegion.index) { r_pos.x = rRegion.sx; r_pos.y = rRegion.sy; r_pos.z = 0; return true; } } return false; } bool SECTREE_MANAGER::GetMapBasePosition(long x, long y, PIXEL_POSITION & r_pos) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (x >= rRegion.sx && y >= rRegion.sy && x < rRegion.ex && y < rRegion.ey) { r_pos.x = rRegion.sx; r_pos.y = rRegion.sy; r_pos.z = 0; return true; } } return false; } const TMapRegion * SECTREE_MANAGER::FindRegionByPartialName(const char* szMapName) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); //if (rRegion.index == lMapIndex) //return &rRegion; if (rRegion.strMapName.find(szMapName)) return &rRegion; // ij½Ì ÇØ¼ ºü¸£°Ô ÇÏÀÚ } return NULL; } const TMapRegion * SECTREE_MANAGER::GetMapRegion(long lMapIndex) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (rRegion.index == lMapIndex) return &rRegion; } return NULL; } int SECTREE_MANAGER::GetMapIndex(long x, long y) { std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (x >= rRegion.sx && y >= rRegion.sy && x < rRegion.ex && y < rRegion.ey) return rRegion.index; } sys_log(0, "SECTREE_MANAGER::GetMapIndex(%d, %d)", x, y); std::vector::iterator i; for (i = m_vec_mapRegion.begin(); i !=m_vec_mapRegion.end(); ++i) { TMapRegion & rRegion = *i; sys_log(0, "%d: (%d, %d) ~ (%d, %d)", rRegion.index, rRegion.sx, rRegion.sy, rRegion.ex, rRegion.ey); } return 0; } int SECTREE_MANAGER::Build(const char * c_pszListFileName, const char* c_pszMapBasePath) { if (true == test_server) { sys_log ( 0, "[bUILD] Build %s %s ", c_pszListFileName, c_pszMapBasePath ); } FILE* fp = fopen(c_pszListFileName, "r"); if (NULL == fp) return 0; char buf[256 + 1]; char szFilename[256]; char szMapName[256]; int iIndex; while (fgets(buf, 256, fp)) { *strrchr(buf, '\n') = '\0'; if (!strncmp(buf, "//", 2) || *buf == '#') continue; sscanf(buf, " %d %s ", &iIndex, szMapName); snprintf(szFilename, sizeof(szFilename), "%s/%s/Setting.txt", c_pszMapBasePath, szMapName); TMapSetting setting; setting.iIndex = iIndex; if (!LoadSettingFile(iIndex, szFilename, setting)) { sys_err("can't load file %s in LoadSettingFile", szFilename); fclose(fp); return 0; } snprintf(szFilename, sizeof(szFilename), "%s/%s/Town.txt", c_pszMapBasePath, szMapName); if (!LoadMapRegion(szFilename, setting, szMapName)) { sys_err("can't load file %s in LoadMapRegion", szFilename); fclose(fp); return 0; } if (true == test_server) sys_log ( 0,"[bUILD] Build %s %s %d ",c_pszMapBasePath, szMapName, iIndex ); // ¸ÕÀú ÀÌ ¼¹ö¿¡¼ ÀÌ ¸ÊÀÇ ¸ó½ºÅ͸¦ ½ºÆùÇØ¾ß Çϴ°¡ È®ÀÎ ÇÑ´Ù. if (map_allow_find(iIndex)) { LPSECTREE_MAP pkMapSectree = BuildSectreeFromSetting(setting); m_map_pkSectree.insert(std::map::value_type(iIndex, pkMapSectree)); snprintf(szFilename, sizeof(szFilename), "%s/%s/server_attr", c_pszMapBasePath, szMapName); LoadAttribute(pkMapSectree, szFilename, setting); snprintf(szFilename, sizeof(szFilename), "%s/%s/regen.txt", c_pszMapBasePath, szMapName); regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY); snprintf(szFilename, sizeof(szFilename), "%s/%s/npc.txt", c_pszMapBasePath, szMapName); regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY); snprintf(szFilename, sizeof(szFilename), "%s/%s/boss.txt", c_pszMapBasePath, szMapName); regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY); snprintf(szFilename, sizeof(szFilename), "%s/%s/stone.txt", c_pszMapBasePath, szMapName); regen_load(szFilename, setting.iIndex, setting.iBaseX, setting.iBaseY); snprintf(szFilename, sizeof(szFilename), "%s/%s/dungeon.txt", c_pszMapBasePath, szMapName); LoadDungeon(iIndex, szFilename); pkMapSectree->Build(); } } fclose(fp); return 1; } bool SECTREE_MANAGER::IsMovablePosition(long lMapIndex, long x, long y) { LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y); if (!tree) return false; return (!tree->IsAttr(x, y, ATTR_BLOCK | ATTR_OBJECT)); } bool SECTREE_MANAGER::GetMovablePosition(long lMapIndex, long x, long y, PIXEL_POSITION & pos) { int i = 0; do { long dx = x + aArroundCoords[i].x; long dy = y + aArroundCoords[i].y; LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, dx, dy); if (!tree) continue; if (!tree->IsAttr(dx, dy, ATTR_BLOCK | ATTR_OBJECT)) { pos.x = dx; pos.y = dy; return true; } } while (++i < ARROUND_COORD_MAX_NUM); pos.x = x; pos.y = y; return false; } bool SECTREE_MANAGER::GetValidLocation(long lMapIndex, long x, long y, long & r_lValidMapIndex, PIXEL_POSITION & r_pos, BYTE empire) { LPSECTREE_MAP pkSectreeMap = GetMap(lMapIndex); if (!pkSectreeMap) { if (lMapIndex >= 10000) { /* long m = lMapIndex / 10000; if (m == 216) { if (GetRecallPositionByEmpire (m, empire, r_pos)) { r_lValidMapIndex = m; return true; } else return false; }*/ return GetValidLocation(lMapIndex / 10000, x, y, r_lValidMapIndex, r_pos); } else { sys_err("cannot find sectree_map by map index %d", lMapIndex); return false; } } long lRealMapIndex = lMapIndex; if (lRealMapIndex >= 10000) lRealMapIndex = lRealMapIndex / 10000; std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (rRegion.index == lRealMapIndex) { LPSECTREE tree = pkSectreeMap->Find(x, y); if (!tree) { sys_err("cannot find tree by %d %d (map index %d)", x, y, lMapIndex); return false; } r_lValidMapIndex = lMapIndex; r_pos.x = x; r_pos.y = y; return true; } } sys_err("invalid location (map index %d %d x %d)", lRealMapIndex, x, y); return false; } bool SECTREE_MANAGER::GetRandomLocation(long lMapIndex, PIXEL_POSITION & r_pos, DWORD dwCurrentX, DWORD dwCurrentY, int iMaxDistance) { LPSECTREE_MAP pkSectreeMap = GetMap(lMapIndex); if (!pkSectreeMap) return false; DWORD x, y; std::vector::iterator it = m_vec_mapRegion.begin(); while (it != m_vec_mapRegion.end()) { TMapRegion & rRegion = *(it++); if (rRegion.index != lMapIndex) continue; int i = 0; while (i++ < 100) { x = number(rRegion.sx + 50, rRegion.ex - 50); y = number(rRegion.sy + 50, rRegion.ey - 50); if (iMaxDistance != 0) { int d; d = abs((float)dwCurrentX - x); if (d > iMaxDistance) { if (x < dwCurrentX) x = dwCurrentX - iMaxDistance; else x = dwCurrentX + iMaxDistance; } d = abs((float)dwCurrentY - y); if (d > iMaxDistance) { if (y < dwCurrentY) y = dwCurrentY - iMaxDistance; else y = dwCurrentY + iMaxDistance; } } LPSECTREE tree = pkSectreeMap->Find(x, y); if (!tree) continue; if (tree->IsAttr(x, y, ATTR_BLOCK | ATTR_OBJECT)) continue; r_pos.x = x; r_pos.y = y; return true; } } return false; } long SECTREE_MANAGER::CreatePrivateMap(long lMapIndex) { if (lMapIndex >= 10000) // 10000¹ø ÀÌ»óÀÇ ¸ÊÀº ¾ø´Ù. (ȤÀº ÀÌ¹Ì private ÀÌ´Ù) return 0; LPSECTREE_MAP pkMapSectree = GetMap(lMapIndex); if (!pkMapSectree) { sys_err("Cannot find map index %d", lMapIndex); return 0; } // Circular private map indexing long base = lMapIndex * 10000; int index_cap = 10000; if ( lMapIndex == 107 || lMapIndex == 108 || lMapIndex == 109 ) { index_cap = (test_server ? 1 : 51); } PrivateIndexMapType::iterator it = next_private_index_map_.find(lMapIndex); if (it == next_private_index_map_.end()) { it = next_private_index_map_.insert(PrivateIndexMapType::value_type(lMapIndex, 0)).first; } int i, next_index = it->second; for (i = 0; i < index_cap; ++i) { if (GetMap(base + next_index) == NULL) { break; // available } if (++next_index >= index_cap) { next_index = 0; } } if (i == index_cap) { // No available index return 0; } long lNewMapIndex = base + next_index; if (++next_index >= index_cap) { next_index = 0; } it->second = next_index; /* int i; for (i = 0; i < 10000; ++i) { if (!GetMap((lMapIndex * 10000) + i)) break; } if ( test_server ) sys_log( 0, "Create Dungeon : OrginalMapindex %d NewMapindex %d", lMapIndex, i ); if ( lMapIndex == 107 || lMapIndex == 108 || lMapIndex == 109 ) { if ( test_server ) { if ( i > 0 ) return NULL; } else { if ( i > 50 ) return NULL; } } if (i == 10000) { sys_err("not enough private map index (map_index %d)", lMapIndex); return 0; } long lNewMapIndex = lMapIndex * 10000 + i; */ pkMapSectree = M2_NEW SECTREE_MAP(*pkMapSectree); m_map_pkSectree.insert(std::map::value_type(lNewMapIndex, pkMapSectree)); sys_log(0, "PRIVATE_MAP: %d created (original %d)", lNewMapIndex, lMapIndex); return lNewMapIndex; } struct FDestroyPrivateMapEntity { void operator() (LPENTITY ent) { if (ent->IsType(ENTITY_CHARACTER)) { LPCHARACTER ch = (LPCHARACTER) ent; sys_log(0, "PRIVAE_MAP: removing character %s", ch->GetName()); if (ch->GetDesc()) DESC_MANAGER::instance().DestroyDesc(ch->GetDesc()); else M2_DESTROY_CHARACTER(ch); } else if (ent->IsType(ENTITY_ITEM)) { LPITEM item = (LPITEM) ent; sys_log(0, "PRIVATE_MAP: removing item %s", item->GetName()); M2_DESTROY_ITEM(item); } else sys_err("PRIVAE_MAP: trying to remove unknown entity %d", ent->GetType()); } }; void SECTREE_MANAGER::DestroyPrivateMap(long lMapIndex) { if (lMapIndex < 10000) // private map Àº À妽º°¡ 10000 ÀÌ»ó ÀÌ´Ù. return; LPSECTREE_MAP pkMapSectree = GetMap(lMapIndex); if (!pkMapSectree) return; // ÀÌ ¸Ê À§¿¡ ÇöÀç Á¸ÀçÇÏ´Â °ÍµéÀ» ÀüºÎ ¾ø¾Ø´Ù. // WARNING: // ÀÌ ¸Ê¿¡ ÀÖÁö¸¸ ¾î¶² Sectree¿¡µµ Á¸ÀçÇÏÁö ¾ÊÀ» ¼ö ÀÖÀ½ // µû¶ó¼ ¿©±â¼ delete ÇÒ ¼ö ¾øÀ¸¹Ç·Î Æ÷ÀÎÅͰ¡ ±úÁú ¼ö ÀÖÀ¸´Ï // º°µµ 󸮸¦ ÇØ¾ßÇÔ FDestroyPrivateMapEntity f; pkMapSectree->for_each(f); m_map_pkSectree.erase(lMapIndex); M2_DELETE(pkMapSectree); sys_log(0, "PRIVATE_MAP: %d destroyed", lMapIndex); } TAreaMap& SECTREE_MANAGER::GetDungeonArea(long lMapIndex) { itertype(m_map_pkArea) it = m_map_pkArea.find(lMapIndex); if (it == m_map_pkArea.end()) { return m_map_pkArea[-1]; // Àӽ÷Πºó Area¸¦ ¸®ÅÏ } return it->second; } void SECTREE_MANAGER::SendNPCPosition(LPCHARACTER ch) { LPDESC d = ch->GetDesc(); if (!d) return; long lMapIndex = ch->GetMapIndex(); if (m_mapNPCPosition[lMapIndex].empty()) return; TEMP_BUFFER buf; TPacketGCNPCPosition p; p.header = HEADER_GC_NPC_POSITION; p.count = m_mapNPCPosition[lMapIndex].size(); TNPCPosition np; // TODO m_mapNPCPosition[lMapIndex] ¸¦ º¸³»ÁÖ¼¼¿ä itertype(m_mapNPCPosition[lMapIndex]) it; for (it = m_mapNPCPosition[lMapIndex].begin(); it != m_mapNPCPosition[lMapIndex].end(); ++it) { np.bType = it->bType; strlcpy(np.name, it->name, sizeof(np.name)); np.x = it->x; np.y = it->y; buf.write(&np, sizeof(np)); } p.size = sizeof(p) + buf.size(); if (buf.size()) { d->BufferedPacket(&p, sizeof(TPacketGCNPCPosition)); d->Packet(buf.read_peek(), buf.size()); } else d->Packet(&p, sizeof(TPacketGCNPCPosition)); } void SECTREE_MANAGER::InsertNPCPosition(long lMapIndex, BYTE bType, const char* szName, long x, long y) { m_mapNPCPosition[lMapIndex].push_back(npc_info(bType, szName, x, y)); } BYTE SECTREE_MANAGER::GetEmpireFromMapIndex(long lMapIndex) { if (lMapIndex >= 1 && lMapIndex <= 20) return 1; if (lMapIndex >= 21 && lMapIndex <= 40) return 2; if (lMapIndex >= 41 && lMapIndex <= 60) return 3; if ( lMapIndex == 184 || lMapIndex == 185 ) return 1; if ( lMapIndex == 186 || lMapIndex == 187 ) return 2; if ( lMapIndex == 188 || lMapIndex == 189 ) return 3; switch ( lMapIndex ) { case 190 : return 1; case 191 : return 2; case 192 : return 3; } return 0; } class FRemoveIfAttr { public: FRemoveIfAttr(LPSECTREE pkTree, DWORD dwAttr) : m_pkTree(pkTree), m_dwCheckAttr(dwAttr) { } void operator () (LPENTITY entity) { if (!m_pkTree->IsAttr(entity->GetX(), entity->GetY(), m_dwCheckAttr)) return; if (entity->IsType(ENTITY_ITEM)) { M2_DESTROY_ITEM((LPITEM) entity); } else if (entity->IsType(ENTITY_CHARACTER)) { LPCHARACTER ch = (LPCHARACTER) entity; if (ch->IsPC()) { PIXEL_POSITION pos; if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos)) ch->WarpSet(pos.x, pos.y); else ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire())); } else ch->Dead(); } } LPSECTREE m_pkTree; DWORD m_dwCheckAttr; }; bool SECTREE_MANAGER::ForAttrRegionCell( long lMapIndex, long lCX, long lCY, DWORD dwAttr, EAttrRegionMode mode ) { SECTREEID id; id.coord.x = lCX / (SECTREE_SIZE / CELL_SIZE); id.coord.y = lCY / (SECTREE_SIZE / CELL_SIZE); long lTreeCX = id.coord.x * (SECTREE_SIZE / CELL_SIZE); long lTreeCY = id.coord.y * (SECTREE_SIZE / CELL_SIZE); LPSECTREE pSec = Get( lMapIndex, id.package ); if ( !pSec ) return false; switch (mode) { case ATTR_REGION_MODE_SET: pSec->SetAttribute( lCX - lTreeCX, lCY - lTreeCY, dwAttr ); break; case ATTR_REGION_MODE_REMOVE: pSec->RemoveAttribute( lCX - lTreeCX, lCY - lTreeCY, dwAttr ); break; case ATTR_REGION_MODE_CHECK: if ( pSec->IsAttr( lCX * CELL_SIZE, lCY * CELL_SIZE, ATTR_OBJECT ) ) return true; break; default: sys_err("Unknown region mode %u", mode); break; } return false; } bool SECTREE_MANAGER::ForAttrRegionRightAngle( long lMapIndex, long lCX, long lCY, long lCW, long lCH, long lRotate, DWORD dwAttr, EAttrRegionMode mode ) { if (1 == lRotate/90 || 3 == lRotate/90) { for (int x = 0; x < lCH; ++x) for (int y = 0; y < lCW; ++y) { if ( ForAttrRegionCell( lMapIndex, lCX + x, lCY + y, dwAttr, mode ) ) return true; } } if (0 == lRotate/90 || 2 == lRotate/90) { for (int x = 0; x < lCW; ++x) for (int y = 0; y < lCH; ++y) { if ( ForAttrRegionCell( lMapIndex, lCX + x, lCY + y, dwAttr, mode) ) return true; } } return mode == ATTR_REGION_MODE_CHECK ? false : true; } #define min( l, r ) ((l) < (r) ? (l) : (r)) #define max( l, r ) ((l) < (r) ? (r) : (l)) bool SECTREE_MANAGER::ForAttrRegionFreeAngle( long lMapIndex, long lCX, long lCY, long lCW, long lCH, long lRotate, DWORD dwAttr, EAttrRegionMode mode ) { float fx1 = (-lCW/2) * sinf(float(lRotate)/180.0f*3.14f) + (-lCH/2) * cosf(float(lRotate)/180.0f*3.14f); float fy1 = (-lCW/2) * cosf(float(lRotate)/180.0f*3.14f) - (-lCH/2) * sinf(float(lRotate)/180.0f*3.14f); float fx2 = (+lCW/2) * sinf(float(lRotate)/180.0f*3.14f) + (-lCH/2) * cosf(float(lRotate)/180.0f*3.14f); float fy2 = (+lCW/2) * cosf(float(lRotate)/180.0f*3.14f) - (-lCH/2) * sinf(float(lRotate)/180.0f*3.14f); float fx3 = (-lCW/2) * sinf(float(lRotate)/180.0f*3.14f) + (+lCH/2) * cosf(float(lRotate)/180.0f*3.14f); float fy3 = (-lCW/2) * cosf(float(lRotate)/180.0f*3.14f) - (+lCH/2) * sinf(float(lRotate)/180.0f*3.14f); float fx4 = (+lCW/2) * sinf(float(lRotate)/180.0f*3.14f) + (+lCH/2) * cosf(float(lRotate)/180.0f*3.14f); float fy4 = (+lCW/2) * cosf(float(lRotate)/180.0f*3.14f) - (+lCH/2) * sinf(float(lRotate)/180.0f*3.14f); float fdx1 = fx2 - fx1; float fdy1 = fy2 - fy1; float fdx2 = fx1 - fx3; float fdy2 = fy1 - fy3; if (0 == fdx1 || 0 == fdx2) { sys_err( "SECTREE_MANAGER::ForAttrRegion - Unhandled exception. MapIndex: %d", lMapIndex ); return false; } float fTilt1 = float(fdy1) / float(fdx1); float fTilt2 = float(fdy2) / float(fdx2); float fb1 = fy1 - fTilt1*fx1; float fb2 = fy1 - fTilt2*fx1; float fb3 = fy4 - fTilt1*fx4; float fb4 = fy4 - fTilt2*fx4; float fxMin = min(fx1, min(fx2, min(fx3, fx4))); float fxMax = max(fx1, max(fx2, max(fx3, fx4))); for (int i = int(fxMin); i < int(fxMax); ++i) { float fyValue1 = fTilt1*i + min(fb1, fb3); float fyValue2 = fTilt2*i + min(fb2, fb4); float fyValue3 = fTilt1*i + max(fb1, fb3); float fyValue4 = fTilt2*i + max(fb2, fb4); float fMinValue; float fMaxValue; if (abs(int(fyValue1)) < abs(int(fyValue2))) fMaxValue = fyValue1; else fMaxValue = fyValue2; if (abs(int(fyValue3)) < abs(int(fyValue4))) fMinValue = fyValue3; else fMinValue = fyValue4; for (int j = int(min(fMinValue, fMaxValue)); j < int(max(fMinValue, fMaxValue)); ++j) { if ( ForAttrRegionCell( lMapIndex, lCX + (lCW / 2) + i, lCY + (lCH / 2) + j, dwAttr, mode ) ) return true; } } return mode == ATTR_REGION_MODE_CHECK ? false : true; } bool SECTREE_MANAGER::ForAttrRegion(long lMapIndex, long lStartX, long lStartY, long lEndX, long lEndY, long lRotate, DWORD dwAttr, EAttrRegionMode mode) { LPSECTREE_MAP pkMapSectree = GetMap(lMapIndex); if (!pkMapSectree) { sys_err("Cannot find SECTREE_MAP by map index %d", lMapIndex); return mode == ATTR_REGION_MODE_CHECK ? true : false; } // // ¿µ¿ªÀÇ ÁÂÇ¥¸¦ Cell ÀÇ Å©±â¿¡ ¸ÂÃç È®ÀåÇÑ´Ù. // lStartX -= lStartX % CELL_SIZE; lStartY -= lStartY % CELL_SIZE; lEndX += lEndX % CELL_SIZE; lEndY += lEndY % CELL_SIZE; // // Cell ÁÂÇ¥¸¦ ±¸ÇÑ´Ù. // long lCX = lStartX / CELL_SIZE; long lCY = lStartY / CELL_SIZE; long lCW = (lEndX - lStartX) / CELL_SIZE; long lCH = (lEndY - lStartY) / CELL_SIZE; sys_log(1, "ForAttrRegion %d %d ~ %d %d", lStartX, lStartY, lEndX, lEndY); lRotate = lRotate % 360; if (0 == lRotate % 90) return ForAttrRegionRightAngle( lMapIndex, lCX, lCY, lCW, lCH, lRotate, dwAttr, mode ); return ForAttrRegionFreeAngle( lMapIndex, lCX, lCY, lCW, lCH, lRotate, dwAttr, mode ); } bool SECTREE_MANAGER::SaveAttributeToImage(int lMapIndex, const char * c_pszFileName, LPSECTREE_MAP pMapSrc) { LPSECTREE_MAP pMap = SECTREE_MANAGER::GetMap(lMapIndex); if (!pMap) { if (pMapSrc) pMap = pMapSrc; else { sys_err("cannot find sectree_map %d", lMapIndex); return false; } } int iMapHeight = pMap->m_setting.iHeight / 128 / 200; int iMapWidth = pMap->m_setting.iWidth / 128 / 200; if (iMapHeight < 0 || iMapWidth < 0) { sys_err("map size error w %d h %d", iMapWidth, iMapHeight); return false; } sys_log(0, "SaveAttributeToImage w %d h %d file %s", iMapWidth, iMapHeight, c_pszFileName); CTargaImage image; image.Create(512 * iMapWidth, 512 * iMapHeight); sys_log(0, "1"); DWORD * pdwDest = (DWORD *) image.GetBasePointer(); int pixels = 0; int x, x2; int y, y2; sys_log(0, "2 %p", pdwDest); DWORD * pdwLine = M2_NEW DWORD[sECTREE_SIZE / CELL_SIZE]; for (y = 0; y < 4 * iMapHeight; ++y) { for (y2 = 0; y2 < SECTREE_SIZE / CELL_SIZE; ++y2) { for (x = 0; x < 4 * iMapWidth; ++x) { SECTREEID id; id.coord.x = x + pMap->m_setting.iBaseX / SECTREE_SIZE; id.coord.y = y + pMap->m_setting.iBaseY / SECTREE_SIZE; LPSECTREE pSec = pMap->Find(id.package); if (!pSec) { sys_err("cannot get sectree for %d %d %d %d", id.coord.x, id.coord.y, pMap->m_setting.iBaseX, pMap->m_setting.iBaseY); continue; } pSec->m_pkAttribute->CopyRow(y2, pdwLine); if (!pdwLine) { sys_err("cannot get attribute line pointer"); M2_DELETE_ARRAY(pdwLine); continue; } for (x2 = 0; x2 < SECTREE_SIZE / CELL_SIZE; ++x2) { DWORD dwColor; if (IS_SET(pdwLine[x2], ATTR_WATER)) dwColor = 0xff0000ff; else if (IS_SET(pdwLine[x2], ATTR_BANPK)) dwColor = 0xff00ff00; else if (IS_SET(pdwLine[x2], ATTR_BLOCK)) dwColor = 0xffff0000; else dwColor = 0xffffffff; *(pdwDest++) = dwColor; pixels++; } } } } M2_DELETE_ARRAY(pdwLine); sys_log(0, "3"); if (image.Save(c_pszFileName)) { sys_log(0, "SECTREE: map %d attribute saved to %s (%d bytes)", lMapIndex, c_pszFileName, pixels); return true; } else { sys_err("cannot save file, map_index %d filename %s", lMapIndex, c_pszFileName); return false; } } struct FPurgeMonsters { void operator() (LPENTITY ent) { if ( ent->IsType(ENTITY_CHARACTER) == true ) { LPCHARACTER lpChar = (LPCHARACTER)ent; #ifdef NEW_PET_SYSTEM if (lpChar->IsMonster() == true && !lpChar->IsPet() && !lpChar->IsNewPet()) #else if ( lpChar->IsMonster() == true && !lpChar->IsPet()) #endif { M2_DESTROY_CHARACTER(lpChar); } } } }; void SECTREE_MANAGER::PurgeMonstersInMap(long lMapIndex) { LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(lMapIndex); if ( sectree != NULL ) { struct FPurgeMonsters f; sectree->for_each( f ); } } struct FPurgeStones { void operator() (LPENTITY ent) { if ( ent->IsType(ENTITY_CHARACTER) == true ) { LPCHARACTER lpChar = (LPCHARACTER)ent; if ( lpChar->IsStone() == true ) { M2_DESTROY_CHARACTER(lpChar); } } } }; void SECTREE_MANAGER::PurgeStonesInMap(long lMapIndex) { LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(lMapIndex); if ( sectree != NULL ) { struct FPurgeStones f; sectree->for_each( f ); } } struct FPurgeNPCs { void operator() (LPENTITY ent) { if ( ent->IsType(ENTITY_CHARACTER) == true ) { LPCHARACTER lpChar = (LPCHARACTER)ent; #ifdef NEW_PET_SYSTEM if (lpChar->IsNPC() == true && !lpChar->IsPet() && !lpChar->IsNewPet()) #else if ( lpChar->IsNPC() == true && !lpChar->IsPet()) #endif { M2_DESTROY_CHARACTER(lpChar); } } } }; void SECTREE_MANAGER::PurgeNPCsInMap(long lMapIndex) { LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(lMapIndex); if ( sectree != NULL ) { struct FPurgeNPCs f; sectree->for_each( f ); } } struct FCountMonsters { std::map m_map_Monsters; void operator() (LPENTITY ent) { if ( ent->IsType(ENTITY_CHARACTER) == true ) { LPCHARACTER lpChar = (LPCHARACTER)ent; if ( lpChar->IsMonster() == true ) { m_map_Monsters[lpChar->GetVID()] = lpChar->GetVID(); } } } }; size_t SECTREE_MANAGER::GetMonsterCountInMap(long lMapIndex) { LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(lMapIndex); if ( sectree != NULL ) { struct FCountMonsters f; sectree->for_each( f ); return f.m_map_Monsters.size(); } return 0; } struct FCountSpecifiedMonster { DWORD SpecifiedVnum; size_t cnt; FCountSpecifiedMonster(DWORD id) : SpecifiedVnum(id), cnt(0) {} void operator() (LPENTITY ent) { if (true == ent->IsType(ENTITY_CHARACTER)) { LPCHARACTER pChar = static_cast(ent); if (true == pChar->IsStone()) { if (pChar->GetMobTable().dwVnum == SpecifiedVnum) cnt++; } } } }; size_t SECTREE_MANAGER::GetMonsterCountInMap(long lMapIndex, DWORD dwVnum) { LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(lMapIndex); if (NULL != sectree) { struct FCountSpecifiedMonster f(dwVnum); sectree->for_each( f ); return f.cnt; } return 0; }Voici les modifications à effectuer:
// 1) Search: FCountSpecifiedMonster(DWORD id) : SpecifiedVnum(id), cnt(0) {} // 2) Replace with: #ifdef __MELEY_LAIR_DUNGEON__ bool bForceVnum; FCountSpecifiedMonster(DWORD id, bool force) : SpecifiedVnum(id), cnt(0), bForceVnum(force) {} #else FCountSpecifiedMonster(DWORD id) : SpecifiedVnum(id), cnt(0) {} #endif // 1) Search: LPCHARACTER pChar = static_cast(ent); if (true == pChar->IsStone()) { if (pChar->GetMobTable().dwVnum == SpecifiedVnum) cnt++; } // 2) After this make a new line and paste: #ifdef __MELEY_LAIR_DUNGEON__ else if ((bForceVnum) && (pChar->IsNPC())) { if (pChar->GetMobTable().dwVnum == SpecifiedVnum) cnt++; } #endif // 1) Search: size_t SECTREE_MANAGER::GetMonsterCountInMap(long lMapIndex, DWORD dwVnum) // 2) Replace with: #ifdef __MELEY_LAIR_DUNGEON__ size_t SECTREE_MANAGER::GetMonsterCountInMap(long lMapIndex, DWORD dwVnum, bool bForceVnum) #else size_t SECTREE_MANAGER::GetMonsterCountInMap(long lMapIndex, DWORD dwVnum) #endif // 1) Search: struct FCountSpecifiedMonster f(dwVnum); // 2) Replace with: #ifdef __MELEY_LAIR_DUNGEON__ struct FCountSpecifiedMonster f(dwVnum, bForceVnum); #else struct FCountSpecifiedMonster f(dwVnum); #endifMerci beaucoup d'avance à ceux qui m'aideront!
Lien vers le commentaire
Partager sur d’autres sites
Meilleurs contributeurs dans cette question
2
2
1
1
Jours populaires
le 22 mai
7
Meilleurs contributeurs dans cette question
Mitsou 2 messages
CHAPPiE 2 messages
Sgt Fatality 1 message
Kijaru 1 message
Jours populaires
le 22 mai 2017
7 messages
6 réponses à cette question
Messages recommandés