Lonca İstatistikleri (guild stats)

  • Konbuyu başlatan Konbuyu başlatan Admin
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 0
  • Görüntüleme Görüntüleme 40

Admin

Metin2Lobby
Yönetici
Founder
Katılım
6 Mayıs 2022
Mesajlar
52,647
Ticaret : 1 / 0 / 0
guild guide.cpp:

war_map.h

search

private:
TWarMapInfo m_kMapInfo;
bool m_bEnded;

LPEVENT m_pkBeginEvent;
LPEVENT m_pkTimeoutEvent;
LPEVENT m_pkEndEvent;
LPEVENT m_pkResetFlagEvent;

add under

#ifndef DISABLE_WAR_BOARD
public:
typedef struct SMemberStats
{
std::string strPlayerName;
DWORD dwGuildId;

BYTE byLevel;
DWORD dwKills;
DWORD dwDeaths;
unsigned long long ullDamage;

SMemberStats() :
dwGuildId(0), byLevel(0), dwKills(0),
dwDeaths(0), ullDamage(0) {}
} TMemberStats;

typedef std::map<DWORD, TMemberStats *> TMemberStatsMap;

TMemberStats * RegisterMemberStats(CHARACTER * ch);
TMemberStats * GetMemberStats(CHARACTER * ch);
void SendStats(TMemberStats * pStats);
void SendStatusBoard(CHARACTER * ch);

private:
TMemberStatsMap map_MemberStats;
#endif


search

#include "locale_service.h"

add under

#include <boost/algorithm/string/replace.hpp>

search

void CWarMap::UpdateUserCount()
{
FSendUserCount f(
m_TeamData[0].dwID,
m_TeamData[0].GetAccumulatedJoinerCount(),
m_TeamData[1].dwID,
m_TeamData[1].GetAccumulatedJoinerCount(),
m_iObserverCount);

std::for_each(m_set_pkChr.begin(), m_set_pkChr.end(), f);
}

add under

#ifndef DISABLE_WAR_BOARD
CWarMap::TMemberStats * CWarMap::RegisterMemberStats(CHARACTER * ch)
{
DWORD dwPlayerID = ch->GetPlayerID();

CWarMap::TMemberStats * pStats = M2_NEW CWarMap::TMemberStats;
pStats->strPlayerName = ch->GetName();
pStats->byLevel = ch->GetLevel();

CGuild * pGuild = ch->GetGuild();

if (pGuild)
pStats->dwGuildId = pGuild->GetID();

boost::algorithm::replace_all(pStats->strPlayerName, " ", "_");
map_MemberStats.insert(CWarMap::TMemberStatsMap::value_type(dwPlayerID, pStats));

return pStats;
}

CWarMap::TMemberStats * CWarMap::GetMemberStats(CHARACTER * ch)
{
CWarMap::TMemberStats * pStats;

if (!ch)
return pStats;

DWORD dwPlayerID = ch->GetPlayerID();
CWarMap::TMemberStatsMap::iterator entry = map_MemberStats.find(dwPlayerID);

if (entry == map_MemberStats.end())
pStats = RegisterMemberStats(ch);
else
pStats = entry->second;

return pStats;
}

namespace
{
struct FScoreBoard
{
FScoreBoard(CWarMap::TMemberStats * pStats) : m_pStats(pStats) {}

void operator() (LPCHARACTER ch)
{
if (!ch || !m_pStats)
return;

ch->ChatPacket(CHAT_TYPE_COMMAND, "warboard update|%u|%s|%u|%u|%d|%llu", m_pStats->dwGuildId, m_pStats->strPlayerName.c_str(), m_pStats->dwKills, m_pStats->dwDeaths, m_pStats->byLevel, m_pStats->ullDamage);
}

CWarMap::TMemberStats * m_pStats;
};
}

void CWarMap::SendStats(CWarMap::TMemberStats * pStats)
{
FScoreBoard f(pStats);
std::for_each(m_set_pkChr.begin(), m_set_pkChr.end(), f);
}

void CWarMap::SendStatusBoard(CHARACTER * ch)
{
if (!ch)
return;

for (CWarMap::TMemberStatsMap::iterator it = map_MemberStats.begin(); it != map_MemberStats.end(); ++it)
{
CWarMap::TMemberStats * pStats = it->second;

if (!pStats)
continue;

ch->ChatPacket(CHAT_TYPE_COMMAND, "warboard update|%u|%s|%u|%u|%d|%llu", pStats->dwGuildId, pStats->strPlayerName.c_str(), pStats->dwKills, pStats->dwDeaths, pStats->byLevel, pStats->ullDamage);
}
}
#endif

search

if (isWarMember && gid != m_TeamData[0].dwID && gid != m_TeamData[1].dwID)
{
ch->SetQuestFlag("war.is_war_member", 0);
isWarMember = false;
}

add under

#ifndef DISABLE_WAR_BOARD
ch->ChatPacket(CHAT_TYPE_COMMAND, "warboard versus|%u|%s|%u|%s", m_TeamData[0].dwID, m_TeamData[0].pkGuild->GetName(), m_TeamData[1].dwID, m_TeamData[1].pkGuild->GetName());
#endif

search

m_set_pkChr.insert(ch);

add under

#ifndef DISABLE_WAR_BOARD
if (isWarMember)
{
CWarMap::TMemberStats * pStats = RegisterMemberStats(ch);
SendStats(pStats);
}

SendStatusBoard(ch);

ch->ChatPacket(CHAT_TYPE_COMMAND, "warboard toggle|1");
#endif


search

if (!GetTeamIndex(dwDeadGuild, idx))
return;

add under

#ifndef DISABLE_WAR_BOARD
if (killer)
{
TMemberStats * pStats = GetMemberStats(killer);
pStats->dwKills++;
SendStats(pStats);
}

if (ch)
{
TMemberStats * pStats = GetMemberStats(ch);
pStats->dwDeaths++;
SendStats(pStats);
}
#endif

char_battle.cpp

search

if (!cannot_dead)
{
PointChange(POINT_HP, -dam, false);
}

add upper

#ifndef DISABLE_WAR_BOARD
if (pAttacker)
{
CWarMap * pWarMap = pAttacker->GetWarMap();

if (pWarMap && pWarMap == GetWarMap())
{
CWarMap::TMemberStats * pStats = pWarMap->GetMemberStats(pAttacker);
pStats->ullDamage += (unsigned long long) dam;
pWarMap->SendStats(pStats);
}
}
#endif



char.cpp

search

void CHARACTER::SetWarMap(CWarMap * pWarMap)
{

change for

void CHARACTER::SetWarMap(CWarMap * pWarMap)
{
#ifndef DISABLE_WAR_BOARD
ChatPacket(CHAT_TYPE_COMMAND, "warboard toggle|0");
#endif


////////////////

clientpart

root -> constinfo.py

add

wndWarBoard = None
CanOpen = 0

root -> game.py

search import interfaceModule

add under

import uiWarBoard

search

self.playerGauge = None

add under

constInfo.wndWarBoard = uiWarBoard.WarBoardWindow()

search

def OnPressEscapeKey(self):

add on this function

if constInfo.wndWarBoard.IsShow():
constInfo.wndWarBoard.Close()
return

search

"ConsoleEnable" : self.__Console_Enable,

add under

"warboard" : self.__WarBoard,
"CanOpenWarBoard" : self.CanOpenWarBoard,
"CantOpenWarBoard" : self.CantOpenWarBoard,

search

def __ProcessPreservedServerCommand(self):

add under function

def __WarBoard(self, input):
constInfo.wndWarBoard.Handle(input)

def CanOpenWarBoard(self):
constInfo.CanOpen = 1

def CantOpenWarBoard(self):
constInfo.CanOpen = 0


def OnKeyDown(self, key):

edit like this:

def OnKeyDown(self, key):
if self.interface.wndWeb and self.interface.wndWeb.IsShow():
return

if key == app.DIK_ESC:
self.RequestDropItem(False)
constInfo.SET_ITEM_QUESTION_DIALOG_STATUS(0)

if key == app.DIK_TAB and constInfo.wndWarBoard: // war board
if not constInfo.wndWarBoard.Open():
self.teleport.Open()
return True

try:
self.onPressKeyDict[key]()
except KeyError:
pass
except:
raise

return True



and uiwarboard.py paste on /root/

uiwarboard.py:

#
# Copyright (c) 2017 by Adams
#
# Niniejszy kod jest chroniony prawem autorskim.
# Wszelkie kopiowanie oraz u¿ytkowanie bez zgody autora
# zabronione pod piecz¹ Kodeksu Karnego - ustaw o prawie autorskim.
#

import ui
import net
import grp
import uiToolTip
import component
import constInfo
import item
import player
import chr
import chat
import localeInfo

BOARD_WIDTH = 465
PLAYER_LIMIT = 10

class GuildWarPlayer(ui.Window):

NEGATIVE_COLOR = grp.GenerateColor(0.9, 0.4745, 0.4627, 1.0)
POSITIVE_COLOR = grp.GenerateColor(0.5411, 0.7254, 0.5568, 1.0)
TITLE_COLOR = grp.GenerateColor(0.9490, 0.9058, 0.7568, 1.0)
SPECIAL_POSITIVE_COLOR = grp.GenerateColor(0.8824, 0.9804, 0.8824, 1.0)

def __init__(self):
ui.Window.__init__(self)

self.name = ""
self.kills = 0
self.deaths = 0
self.balance = 0
self.damage = "0"
self.level = 0

self.__BuildWindow()

def __del(self):
ui.Window.__del__(self)

def __TextLine(self, text, x, color = None, centered = False):
element = self.component.TextLine(self, "", x, 0, None)
element.SetFontName("Tahoma:14")
element.SetText(text)

if centered:
element.SetHorizontalAlignCenter()

if color:
element.SetPackedFontColor(color)

return element

def __BuildWindow(self):
c = component.Component()
self.component = c

self.nameLine = self.__TextLine(self.GetName(), 5)
self.killsLine = self.__TextLine(self.GetKills(), 126, self.POSITIVE_COLOR, True)
self.deathsLine = self.__TextLine(self.GetDeaths(), 185, self.NEGATIVE_COLOR, True)
self.levelLine = self.__TextLine(self.GetLevel(), 239, None, True)
self.damageLine = self.__TextLine(self.GetDamage(), 358, None, True)

self.Show()

def SetName(self, name):
self.name = str(name)

def GetName(self):
return self.name

def SetKills(self, kills):
self.kills = int(kills)
self.CalculateBalance()

def GetKills(self):
return self.kills

def SetDeaths(self, deaths):
self.deaths = int(deaths)
self.CalculateBalance()

def GetDeaths(self):
return self.deaths

def CalculateBalance(self):
self.balance = max(0, int(self.GetKills() - self.GetDeaths()))

def GetBalance(self):
return self.balance

def SetDamage(self, damage):
self.damage = int(damage)

def GetDamage(self):
return self.damage

def SetLevel(self, level):
self.level = int(level)

def GetLevel(self):
return self.level

def Render(self):
name = self.GetName()
self.killsLine.SetText(str(self.GetKills()))
self.deathsLine.SetText(str(self.GetDeaths()))
self.levelLine.SetText(str(self.GetLevel()))

n = self.GetDamage()
self.damageLine.SetText("%s" % ('.'.join([ i-3<0 and str(n)[:i] or str(n)[i-3:i] for i in range(len(str(n))%3, len(str(n))+1, 3) if i ])))

if player.GetName() == name:
self.nameLine.SetText("> %s <" % name)
self.nameLine.SetPackedFontColor(self.SPECIAL_POSITIVE_COLOR)
else:
self.nameLine.SetText(name)
self.nameLine.SetPackedFontColor(self.TITLE_COLOR)

class GuildWarBoard(ui.Window):

GOLD_COLOR = grp.GenerateColor(1.0, 0.7843, 0.0, 1.0)

def __init__(self, parent):
self.players = [*]
self.guild_id = 0
self.guild_name = "Guild"

ui.Window.__init__(self)
self.SetParent(parent)
self.__BuildWindow()

def __del__(self):
ui.Window.__del__(self)

def SetGuildName(self, name):
self.guild_name = name
self.title.SetText("%s" % name)

def GetGuildName(self):
return self.guild_name

def SetGuildId(self, id):
self.guild_id = int(id)

if self.mark:
self.mark.SetIndex(id)

def GetGuildId(self):
return self.guild_id

def __CreatePlayer(self, name):
for player in self.players:
if player.GetName() == name:
return player

player = GuildWarPlayer()
player.SetParent(self)
player.SetName(name)
player.Show()

self.players.append(player)
return player

def AddPlayer(self, name, kills = 0, deaths = 0, level = 0, damage = 0):
player = self.__CreatePlayer(name)

player.SetKills(kills)
player.SetDeaths(deaths)
player.SetLevel(level)
player.SetDamage(damage)

self.Render()

def ClearPlayers(self):
self.players = [*]

def GetMVP(self):
players = sorted(self.players, key = lambda player: (player.balance, player.damage), reverse = True)

if len(players) == 0:
return "~"

return players[0].GetName()

def GetTotalKills(self):
x = 0
for player in self.players:
x += player.GetKills()
return x

def Render(self):
players = sorted(self.players, key = lambda player: (player.balance, player.damage), reverse = True)
players = players[:pLAYER_LIMIT]

y = 29

for player in players:
player.SetPosition(0, y)
player.Render()
y += 20

self.SetSize(BOARD_WIDTH - 22, y + 5)

def __BuildWindow(self):
c = component.Component()
self.SetPosition(11, 15)

mark = ui.MarkBox()
mark.SetParent(self)
mark.SetPosition(3, 3)
mark.SetIndex(self.guild_id)
mark.SetScale(1)
mark.Show()
self.mark = mark

title = c.TextLine(self, "", 22, 0, None)
title.SetPackedFontColor(self.GOLD_COLOR)
title.SetFontName("Tahoma:14")
title.SetText("")
self.title = title

kills = c.TextLine(self, "", 100, 0, None)
kills.SetFontName("Tahoma:14")
kills.SetText("Kills")
self.kills = kills

deaths = c.TextLine(self, "", 170, 0, None)
deaths.SetFontName("Tahoma:14")
deaths.SetText("Death")
self.deaths = deaths

level = c.TextLine(self, "", 223, 0, None)
level.SetFontName("Tahoma:14")
level.SetText("Level")
self.level = level

damage = c.TextLine(self, "", 310, 0, None)
damage.SetFontName("Tahoma:14")
damage.SetText("Total Damage")
self.damage = damage

separator = ui.Line()
separator.SetParent(self)
separator.SetPosition(0, 25)
separator.SetColor(-1124073473)
separator.SetSize(BOARD_WIDTH - 22, 0)
separator.Show()
self.separator = separator

self.Render()

self.component = c
self.Show()

class WarVersusBox(ui.Window):

GOLD_COLOR = grp.GenerateColor(1.0, 0.7843, 0.0, 1.0)
POSITIVE_COLOR = grp.GenerateColor(0.5411, 0.7254, 0.5568, 1.0)

def __init__(self):
self.boards = [*]
self.marks = [*]
self.names = [*]
self.mvps = [*]

ui.Window.__init__(self)
self.__BuildWindow()

def __del__(self):
del self.boards
del self.marks
del self.names
del self.mvps

ui.Window.__del__(self)

def __MarkBox(self, x):
mark = ui.MarkBox()
mark.SetParent(self)
mark.SetPosition(x, 0)
mark.SetIndex(0)
mark.SetScale(3)
mark.Show()

self.marks.append(mark)

def __TextLine(self, text, x, color = None, centered = False):
element = self.component.TextLine(self, "", x, 0, None)
element.SetFontName("Tahoma:14")
element.SetText(text)

if centered:
element.SetHorizontalAlignCenter()

if color:
element.SetPackedFontColor(color)

return element

def __BuildWindow(self):
c = component.Component()

self.__MarkBox(16)
self.__MarkBox(237)

self.names.append(c.TextLine(self, "", 68, 1, None))
self.names.append(c.TextLine(self, "", 289, 1, None))

for name in self.names:
name.SetPackedFontColor(self.GOLD_COLOR)
name.SetFontName("Tahoma:14")

self.mvps.append(c.TextLine(self, "", 68, 17, None))
self.mvps.append(c.TextLine(self, "", 289, 17, None))

for mvp in self.mvps:
mvp.SetPackedFontColor(self.POSITIVE_COLOR)
mvp.SetFontName("Tahoma:14")

self.component = c
self.Show()

def Render(self, y):
self.SetPosition(0, y)

for i, board in enumerate(self.boards):
self.marks.SetIndex(board.GetGuildId())
self.marks.SetScale(3)
self.names.SetText("%s (%d kills)" % (board.GetGuildName(), board.GetTotalKills()))
self.mvps.SetText("MVP: %s" % board.GetMVP())

def SetBoards(self, boards):
self.boards = boards

class WarBoardWindow(ui.ThinBoard):

def __init__(self):
ui.ThinBoard.__init__(self)
self.__BuildWindow()

self.toggle = False

def __del__(self):
ui.ThinBoard.__del__(self)

def __BuildWindow(self):
self.boards = [*]

self.boards.append(GuildWarBoard(self))
self.boards.append(GuildWarBoard(self))

versus = WarVersusBox()
versus.SetParent(self)
versus.SetBoards(self.boards)
self.versus = versus

self.Render()

def Render(self):
y = self.boards[0].GetHeight()
self.boards[1].SetPosition(11, 15 + y + 5)

height = y + self.boards[1].GetHeight() + 20
self.versus.Render(height)

height += 15 * 2 + 15
self.SetSize(BOARD_WIDTH, height)

def AddPlayer(self, guildId, player):
for board in self.boards:
if board.GetGuildId() == guildId:
board.AddPlayer(*player)
return

def Handle(self, input):
input = input.split("|")

if len(input) == 0:
return

if input[0] == "toggle":
self.toggle = bool(input[1])
return

if input[0] == "versus":
self.boards[0].SetGuildId(int(input[1]))
self.boards[0].SetGuildName(input[2])
self.boards[1].SetGuildId(int(input[3]))
self.boards[1].SetGuildName(input[4])
self.versus.SetBoards(self.boards)

for board in self.boards:
board.ClearPlayers()

self.Render()
return

if input[0] == "update":
self.AddPlayer(int(input[1]), input[2:])
self.Render()
return

def IsOnWar(self):
return self.toggle

def Open(self):
if not self.IsOnWar():
return False

self.SetTop()
self.SetCenterPosition()
self.Show()
return True

def Close(self):
if not self.IsShow():
return False

self.Hide()
return True

def OnPressEscapeKey(self):
self.Close()
return True

Metin2 Lonca İstatistikleri (Guild Stats) Sistemi Nasıl Geliştirilir?

Metin2 özel sunucularında loncaların rolü oldukça büyüktür. Loncalar, oyuncuların bir araya gelip ortak hedefler peşinde koşmasını sağlar. Bu bağlamda, lonca istatistikleri (guild stats) sistemi, oyuncuların loncalarının gelişimini takip edebilmesi için kritik öneme sahiptir.

Lonca İstatistikleri Nedir?
Lonca istatistikleri; bir loncanın seviyesi, kazandığı savaşlar, katıldığı turnuvalar, toplam kazanç puanları gibi verileri içerir. Bu veriler, oyuncuların loncasına olan bağlılığını artırır ve rekabet ortamını besler. Bu tür sistemler, Metin2 PvP sunucularında özellikle popülerdir.

Lonca İstatistikleri Nasıl Entegre Edilir?
C++ temelli Metin2 sunucu kaynak kodlarında, lonca verileri genellikle 'db' (veritabanı) ve 'game' sunucusu arasında senkronize edilir. Lonca istatistikleri için özel tablolar oluşturulmalıdır. Örneğin: guild_stats, guild_battles, guild_achievements gibi tablolar veritabanında tanımlanabilir. Bu tablolara yazma ve okuma işlemleri için gerekli fonksiyonlar C++ ile yazılır.

Python Tarafında GUI ile Lonca Verilerini Göstermek
Py ROOT ve UIScript kullanarak, oyuncuların lonca istatistiklerini görüntüleyebileceği bir arayüz tasarlanabilir. Py GUI kullanarak, oyuncuların anlık olarak lonca puanlarını, seviye ilerlemelerini ve turnuva geçmişini görebileceği bir ekran hazırlanabilir. Bu tür sistemler, kullanıcı deneyimini ciddi anlamda artırır.

Martysama ve Diğer Geliştirici Kaynakları
Metin2 geliştiricileri, lonca istatistikleri gibi sistemleri entegre ederken Martysama veya diğer Metin2Dev kaynaklarını kullanabilirler. Bu sistemler genellikle açık kaynak olarak sunulur ve geliştiricilerin projelerine kolayca entegre edilir. Ancak, bu tür sistemlerin güvenliği ve stabilitesi için dikkatli testler yapılmalıdır.

Lonca İstatistikleri ile PvP Sistemlerini Birleştirme
Lonca istatistikleri, turnuva ve savaş sistemleriyle entegre edildiğinde, oyuncular daha fazla motive olur. Her savaş sonucunda lonca puanı artar, seviye atlarsa bonuslar kazanılır. Bu sistemler, Metin2 özel sunucularında oyuncu sadakatini artırmak için etkili bir yöntemdir.

Sonuç
Lonca istatistikleri sistemi, Metin2 özel sunucularında hem teknik hem de oyun içi deneyim açısından büyük önem taşır. Doğru uygulandığında, oyuncuların loncalara olan bağlılığını ve PvP etkinliğini ciddi şekilde artırabilir.


How to Develop Guild Statistics System in Metin2?

In Metin2 private servers, guilds play a significant role. Guilds allow players to come together and pursue common goals. In this context, the guild statistics system is crucial for players to track their guild's progress.

What Are Guild Statistics?
Guild statistics include data such as a guild's level, battles won, tournaments participated in, and total earned points. These metrics increase player loyalty towards their guild and fuel competition. Such systems are especially popular on Metin2 PvP servers.

How to Integrate Guild Statistics?
Within C++ based Metin2 server sources, guild data is typically synchronized between the 'db' (database) and 'game' server. Specific tables must be created for guild stats, like guild_stats, guild_battles, guild_achievements. Functions for reading and writing these tables are written in C++.

Displaying Guild Data with GUI in Python
Using Py ROOT and UIScript, you can design an interface where players can view their guild stats. With Py GUI, a screen showing real-time guild points, level progression, and tournament history can be built. Such interfaces significantly enhance user experience.

Martysama and Other Developer Resources
Developers integrating systems like guild stats often rely on resources like Martysama or other Metin2Dev libraries. These systems are usually open-source and easily integrated into projects. However, careful testing must be done to ensure stability and security.

Integrating Guild Stats with PvP Systems
When combined with tournaments and battle systems, guild statistics motivate players more. After each battle, guild points increase, and upon leveling up, bonuses are awarded. This approach enhances player retention and activity on Metin2 private servers.

Conclusion
The guild statistics system holds great importance both technically and in terms of gameplay in Metin2 private servers. When implemented correctly, it can significantly boost player loyalty to guilds and PvP engagement.
 

Şuan Bu Konuyu Görüntüleyen Kullanıcılar (Toplam : 0, Üye : 0, Misafir : 0)

Geri
Üst Alt