When the host of wtfast blocks a certain connection you can't do anything
Beiträge von Sogma
-
-
Facebook in 2023? I'm not a marketing expert but the company I work for ignores Facebook completely, which didn't harm the business. Since years I met nobody who uses Facebook/TikTok at all.
Are M2 players really that much trapped in the past?
-
Fehlt da etwas in der Vorstellung?
Nach Farmmaps und Levelmaps hört es ja irgendwie auf?
-
Nette Idee, man könnte auch noch den Radius abhängig vom Skilllevel machen (gerade interessant für bpsw. Server mit L-Skills). Und für den Ottonormalverbraucher solltest du wahrscheinlich auch noch einen Empire-Check mit einbauen, da durchschnittliche Metin-Spieler niemanden aus anderen Reichen buffen will.
Empire Check beispiel:
if ((dist != 0 && max > dist) && (pc->second->GetEmpire() == GetEmpire()))
Radius beispiel:
Die cases müssen dann entsprechend ausgearbeitet werden.
GetSkillMasterType kann mit diesen Werten abgefragt werden (definiert in length.h)
-
Hi,
erstmal danke an Steap für den Effekt. Wenn ihr das System einbaut und etwas in die Richtung braucht, dann meldet euch bei ihm! Bitte melden Sie sich an, um diesen Link zu sehen.
Folgendes habe ich hier gemacht:
Bitte melden Sie sich an, um diesen Link zu sehen.
Buff Skills haben einen AoE Effekt, wodurch alle Spieler in einem gesetzten Radius die Buffs bekommen. Das funktioniert, wenn man den Skill auf sich selbst oder auch auf einen anderen Char anwendet.
Ich baue hierbei auf diesem Release von mir auf Bitte melden Sie sich an, um diesen Link zu sehen.
Code: config.cpp- //find:
- void map_allow_copy(long * pl, int size)
- {
- [...]
- }
- //add after:
- #ifdef BUFF_AOE
- static std::set<DWORD> s_set_buffs_aoe;
- void buff_aoe_add(DWORD dwVnum)
- {
- if (buff_aoe_find(dwVnum) == true)
- {
- fprintf(stdout, "!!! FATAL ERROR !!! multiple BUFF_AOE setting!!\n");
- exit(1);
- }
- fprintf(stdout, "BUFF AOE %d\n", dwVnum);
- s_set_buffs_aoe.insert(dwVnum);
- }
- bool buff_aoe_find(DWORD dwVnum)
- {
- if (g_bAuthServer)
- return false;
- if (s_set_buffs_aoe.find(dwVnum) == s_set_buffs_aoe.end())
- return false;
- return true;
- }
- #endif
- //find function
- static bool __LoadGeneralConfigFile(const char* configName)
- //add to loop while (fgets(buf, 256, fp))
- #ifdef BUFF_AOE
- TOKEN("BUFF_AOE")
- {
- char* p = value_string;
- string stNum;
- for (; *p; p++)
- {
- if (isnhspace(*p))
- {
- if (stNum.length())
- {
- DWORD dwVnum = 0;
- str_to_number(dwVnum, stNum.c_str());
- buff_aoe_add(dwVnum);
- stNum.clear();
- }
- }
- else
- stNum += *p;
- }
- if (stNum.length())
- {
- DWORD dwVnum = 0;
- str_to_number(dwVnum, stNum.c_str());
- buff_aoe_add(dwVnum);
- }
- continue;
- }
- #endif
Code: char_skill.cpp- //search in function UseSkill
- if (dwVnum == SKILL_CHAIN)
- {
- ResetChainLightningIndex();
- AddChainLightningExcept(pkVictim);
- }
- //add after
- #ifdef BUFF_AOE
- if ((buff_aoe_find(dwVnum)) && (IS_SET(pkSk->dwFlag, SKILL_FLAG_BUFF_AOE)))
- {
- LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
- if (pMap != NULL)
- {
- FFindPC f;
- pMap->for_each(f);
- if (f.m_mapPC.size() > 0)
- {
- std::map<DWORD, LPCHARACTER>::iterator pc = f.m_mapPC.begin();
- float max = 1500.0f; //Distance for players which are getting buffed
- while (pc != f.m_mapPC.end())
- {
- float dist = DISTANCE_SQRT(GetX() - pc->second->GetX(), GetY() - pc->second->GetY());
- if (dist != 0 && max > dist)
- {
- //if you need/want more conditions add them here, like same empire or level gap
- ComputeSkill(dwVnum, pc->second);
- }
- pc++;
- }
- }
- }
- }
- #endif
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Hinweis: Der ganze Client Kram macht nur Sinn, wenn ihr einen Effekt habt den ihr anzeigen lassen wollt. Der Vollständigkeit halber gebe ich hier aber ein Beispiel mit, wie man das machen KANN.
Code: PythonPlayerModule.cpp- //add new function above void initPlayer
- #ifdef BUFF_AOE
- PyObject* playerIsBuffAOE(PyObject* poSelf, PyObject* poArgs)
- {
- std::set<int> buff_aoe = { 94,95,96 }; //Skills which will get the AoE effect, has to be adjusted
- int dwSkillVnum = 0;
- if (!PyTuple_GetInteger(poArgs,0,&dwSkillVnum))
- {
- return Py_BuildException();
- }
- return Py_BuildValue("b", buff_aoe.find(dwSkillVnum) != buff_aoe.end());
- }
- #endif
- //In function initPlayer, static PyMethodDef s_method[] =
- #ifdef BUFF_AOE
- { "IsBuffAOE", playerIsBuffAOE, METH_VARARGS },
- #endif
Code: root/playersettingmodule.py- //in def __LoadGameShamanEx, Block ## SKILL
- //My example is gicheon skill (crit buff) only, repeat that for each skill you want
- if app.BUFF_AOE:
- if player.IsBuffAOE(96):
- chrmgr.RegisterCacheMotionData(chr.MOTION_MODE_GENERAL, chr.MOTION_SKILL+6, "gicheon_target_aoe.msa")
- else:
- chrmgr.RegisterCacheMotionData(chr.MOTION_MODE_GENERAL, chr.MOTION_SKILL+6, "gicheon_target.msa")
- else:
- chrmgr.RegisterCacheMotionData(chr.MOTION_MODE_GENERAL, chr.MOTION_SKILL+6, "gicheon_target.msa")
Code: pc(2)/shaman/skill/gicheon_target.msa- copy file and save as 'gicheon_target_aoe.msa'
- extend the copied file with an additional effect. Paths to the effect have to be adjusted (Group Event02)
- ScriptType MotionData
- MotionFileName "D:\Ymir Work\pc\shaman\skill\target.GR2"
- MotionDuration 1.666667
- Group MotionEventData
- {
- MotionEventDataCount 3
- Group Event00
- {
- MotionEventType 1
- StartingTime 0.081197
- IndependentFlag 0
- AttachingEnable 0
- AttachingBoneName "Bip01 Head"
- FollowingEnable 0
- EffectFileName "d:/ymir work/pc/shaman/effect/6gicheon_making.mse"
- EffectPosition 0.000000 0.000000 0.000000
- }
- Group Event01
- {
- MotionEventType 10
- StartingTime 1.305758
- EffectFileName "d:/ymir work/pc/shaman/effect/6gicheon_blow.mse"
- EffectPosition 0.000000 0.000000 110.000000
- FollowingEnable 1
- }
- Group Event02
- {
- MotionEventType 1
- StartingTime 0.081197
- IndependentFlag 0
- AttachingEnable 0
- AttachingBoneName "Bip01 Footsteps"
- FollowingEnable 0
- EffectFileName "d:/ymir work/effect/etc/skill_target_indicator/skill_target_indicator.mse"
- EffectPosition 0.000000 0.000000 0.000000
- }
- }
-
In char.h, class CHARACTER
CodeExample usage:
cmd.cpp, struct command_info cmd_info[]
{ "map_info", do_map_info, 0, POS_DEAD, GM_IMPLEMENTOR},
above struct:
ACMD(do_map_info);
file cmd_gm.cpp, new function:
Code- ACMD(do_map_info)
- {
- LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(ch->GetMapIndex());
- if (pMap != NULL)
- {
- CHARACTER::FFindPC f;
- pMap->for_each(f);
- if (f.m_mapPC.size() > 0)
- {
- std::map<DWORD, LPCHARACTER>::iterator pc = f.m_mapPC.begin();
- while (pc != f.m_mapPC.end())
- {
- ch->ChatPacket(CHAT_TYPE_INFO, "%s", pc->second->GetName());
- pc++;
- }
- }
- }
- }
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Edit:
ACMD = #define ACMD(name) void (name)(LPCHARACTER ch, const char *argument, int cmd, int subcmd) in cmd.h
-
Da sind ein paar coole Ideen dabei. Sehe auch kein Problem darin sich an anderen Games wie PoE zu bedienen.
Kannst du das mit dem Lager noch mal genauer erklären?
-
Boot: item rare table size error
Bedeutet, dass deine SQl Tabelle nicht mit der tabledefiniton im source zusammenpasst.
-
Bitte melden Sie sich an, um dieses Medienelement zu sehen.
Bitte melden Sie sich an, um dieses Medienelement zu sehen.
-
Habe ich auch schon überlegt, ggf. mit einem Schieberegler wie bei Chest Stack Open.
MIr ist erstmal noch ein Exploit beim Thema Antiexp Group Extension aufgefallen, wodurch man sich den Gruppen Exp Buff zu Nutze machen kann. Da kümmere ich mich als erstes drum, dann vielleicht das was du hier geschrieben hast.
Würde es folgendermaßen regeln;
Schreibt der Spieler bspw.
Weiße Perle(35) steht im Chat:
Weiße Perle x35 ...
schreibt der Spieler mit einem Stack von bspw. 100 einfach nur
Weiße Perle
entsteht
Weiße Perle x100 ...
weil so Regler usw. denke ich würde Spieler auf Dauer echt nervenDann müsstest du ja automatisch bei einem Chat herauszufinden, ob das Geschriebene ein Item darstellt, oder verstehe ich dich falsch?
-
Ich fände es schöner, wenn der Spieler die Möglichkeit hat zu entscheiden, ob der Count angezeigt wird oder nicht. Sonst muss man das Item immer in ein einzelnes Splitten um es dann im Chat nutzen zu können, da Käufer sonst denken, dass alle verkauft werden. Ich hoffe, das macht Sinn haha Vielleicht ein kleines Popup Fenster, wo man flott eine von zwei Versionen auswählen kann. In den Spieloptionen könnte man dem Spieler die Möglichkeit für Auswahlmenü, Mit Count, Ohne Count geben. Oder Alt + Linksklick für ohne Count, Alt + Rechtsklick für mit Count. Aber vielleicht würde das auch den Rahmen des Releases sprengen.
Danke für den Release!
Habe ich auch schon überlegt, ggf. mit einem Schieberegler wie bei Chest Stack Open.
MIr ist erstmal noch ein Exploit beim Thema Antiexp Group Extension aufgefallen, wodurch man sich den Gruppen Exp Buff zu Nutze machen kann. Da kümmere ich mich als erstes drum, dann vielleicht das was du hier geschrieben hast.
-
Moin, nochmal etwas kleines.
Die Erweiterung sorgt dafür, dass bei stapelbaren Items die Stacksize von der Item Cell, die man im Chat verlinkt, mit ausgegeben wird.
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Ggf. kann man den Code noch verschlanken, da kann sich ja jeder für sich etwas überlegen.
Das Ganze findet im Client Source statt.
Code: PythonPlayerModule.cpp- //Search:
- PyObject * playerGetItemLink(PyObject * poSelf, PyObject * poArgs)
- //replace/adjust function:
- PyObject * playerGetItemLink(PyObject * poSelf, PyObject * poArgs)
- {
- TItemPos Cell;
- switch (PyTuple_Size(poArgs))
- {
- case 1:
- if (!PyTuple_GetInteger(poArgs, 0, &Cell.cell))
- return Py_BuildException();
- break;
- case 2:
- if (!PyTuple_GetByte(poArgs, 0, &Cell.window_type))
- return Py_BuildException();
- if (!PyTuple_GetInteger(poArgs, 1, &Cell.cell))
- return Py_BuildException();
- break;
- default:
- return Py_BuildException();
- }
- const TItemData * pPlayerItem = CPythonPlayer::Instance().GetItemData(Cell);
- CItemData * pItemData = NULL;
- char buf[1024];
- if (pPlayerItem && CItemManager::Instance().GetItemDataPointer(pPlayerItem->vnum, &pItemData))
- {
- char itemlink[256];
- int len;
- bool isAttr = false;
- len = snprintf(itemlink, sizeof(itemlink), "item:%x:%x:%x:%x:%x",
- pPlayerItem->vnum, pPlayerItem->flags,
- pPlayerItem->alSockets[0], pPlayerItem->alSockets[1], pPlayerItem->alSockets[2]);
- for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i)
- {
- // if (pPlayerItem->aAttr[i].bType != 0) // @fixme009 (this line must be commented)
- {
- len += snprintf(itemlink + len, sizeof(itemlink) - len, ":%x:%d",
- pPlayerItem->aAttr[i].bType, pPlayerItem->aAttr[i].sValue);
- isAttr = true;
- }
- }
- if( GetDefaultCodePage() == CP_ARABIC ) {
- if (isAttr)
- //"item:¹øÈ£:Ç÷¡±×:¼ÒÄÏ0:¼ÒÄÏ1:¼ÒÄÏ2"
- snprintf(buf, sizeof(buf), " |h|r[%s]|cffffc700|H%s|h", pItemData->GetName(), itemlink);
- else
- snprintf(buf, sizeof(buf), " |h|r[%s]|cfff1e6c0|H%s|h", pItemData->GetName(), itemlink);
- } else {
- #ifdef HYPERLINK_STACKSIZE
- if (isAttr)
- {
- if (pItemData->IsFlag(pItemData->ITEM_FLAG_STACKABLE))
- {
- snprintf(buf, sizeof(buf), "|cffffc700|H%s|h[%s x%d]|h|r", itemlink, pItemData->GetName(), CPythonPlayer::Instance().GetItemCount(Cell));
- }
- else
- {
- snprintf(buf, sizeof(buf), "|cffffc700|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
- }
- }
- else
- {
- if (pItemData->IsFlag(pItemData->ITEM_FLAG_STACKABLE))
- {
- snprintf(buf, sizeof(buf), "|cfff1e6c0|H%s|h[%s x%d]|h|r", itemlink, pItemData->GetName(), CPythonPlayer::Instance().GetItemCount(Cell));
- }
- else
- {
- snprintf(buf, sizeof(buf), "|cfff1e6c0|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
- }
- }
- #else
- if (isAttr)
- snprintf(buf, sizeof(buf), "|cffffc700|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
- else
- snprintf(buf, sizeof(buf), "|cfff1e6c0|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
- #endif
- }
- }
- else
- buf[0] = '\0';
- return Py_BuildValue("s", buf);
- }
-
Moin, ganz einfache Sache.
Gruppenmitglieder, die Anti EXP aktiviert haben, werden aus dem EXP Share der Gruppe ausgeschlossen.
Wie wird der EXP Share berechnet?
Die Basiserfahrungspunkte werden [...] durch die Anzahl der Gruppenmitglieder geteilt und erst dann werden andere Faktoren wie die Bonus-Exp (z.B. bei zwei Mitgliedern +12%) oder die relative Erfahrung (siehe oben) jeweils für jedes Mitglied verrechnet.
Um die Anti EXP Chars auszuschließen muss das FPartyTotaler struct in der char_battle.cpp angepasst werden. Meine Anti EXP Basis, also das System auf dem ich aufbaue, Bitte melden Sie sich an, um diesen Link zu sehen..
Code: char_battle.cpp- struct FPartyTotaler
- {
- int total;
- int member_count;
- int x, y;
- FPartyTotaler(LPCHARACTER center)
- : total(0), member_count(0), x(center->GetX()), y(center->GetY())
- {};
- void operator () (LPCHARACTER ch)
- {
- if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
- {
- #ifdef ANTIEXP_GROUP_EX
- if (!ch->block_exp)
- {
- total += __GetPartyExpNP(ch->GetLevel());
- ++member_count;
- }
- #else
- total += __GetPartyExpNP(ch->GetLevel());
- ++member_count;
- #endif
- }
- }
- };
Bei Fragen oder Problemen schreibt hier, ich habe das ganze eben nur kurz mit 2 Partymembern getestet:
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Update: Berechnung vom Gruppen-EXP Buff angepasst. (party.cpp). Der EXP Bonus wird auf Basis der Anzahl Gruppenmitglieder in der Nähe des Leaders ermittelt. Die Tabelle dazu ist in constants.cpp, ich benutze bei mir const int CHN_aiPartyBonusExpPercentByMemberCount[9].
Durch die Anpassung werden die Gruppenmitglieder, die Anti-EXP aktiviert haben aus der Anzahl wieder herausgenommen.
Dadurch wird unterbunden, dass man einfach eine volle Gruppe macht, bei 7 Chars EXP deaktiviert und dann den 100% Bonus durch die Gruppe bekommt.
Code: party.cpp- int CParty::ComputePartyBonusExpPercent()
- {
- if (GetNearMemberCount() <= 1)
- return 0;
- LPCHARACTER leader = GetLeaderCharacter();
- int iBonusPartyExpFromItem = 0;
- // UPGRADE_PARTY_BONUS
- int iMemberCount=MIN(8, GetNearMemberCount());
- #ifdef ANTIEXP_GROUP_EX
- //reduce member count for exp bonus when members have anti-exp enabled and are in range
- for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
- {
- TMember& rMember = it->second;
- if (rMember.pCharacter && rMember.pCharacter->block_exp && rMember.bNear)
- iMemberCount -= 1;
- }
- #endif
- if (leader && (leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP) || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_MALL)
- || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_GIFT) || leader->IsEquipUniqueGroup(10010)))
- {
- iBonusPartyExpFromItem = 30;
- }
- return iBonusPartyExpFromItem + CHN_aiPartyBonusExpPercentByMemberCount[iMemberCount];
- // END_OF_UPGRADE_PARTY_BONUS
- }
-
Bitte melden Sie sich an, um dieses Medienelement zu sehen.
-
Einfach so viele Fehler einbauen, dass ohne Support nichts funktioniert
-
Du kannst eine VWK in den Shop packen und dann, wenn das item für den PC erstellt wird, einen zufälligen socket zuweisen. Müsste eigentlich so gehen.
Dann ist das Monster in welches man sich verwandelt zwar random, aber kann man m.M.n so überlegen
-
Do you mean that you want to buy a certain in-game item from the store with another item?
No, he wants to put certain polymorph Items in a shop
-
Bitte melden Sie sich an, um diesen Link zu sehen.
-
Mach ne neue Funktion in der Character Klasse, also in char.h definieren.
Je nachdem was für Mengen du erwartest mach da ein int oder long long Datentyp als return value.
DIe Funktion rufst du dann überall da auf wo du bis jetzt deine Variable amount benutzt.
Es wird sich da nur das Level des Spielers genommen und mit 10 Multipliziert. Ein Level 100 Spieler zahlt also 1000 Gold pro Pull, ein Level 10 Spieler 100.
Bin nur am Handy unterwegs, was die Funktionsdefinition angeht musst du das mal ausprobieren und ggf. noch korrigieren
Danke für deine Erklärung, ich hab das versucht, jedoch bekomme ich das leider nicht ganz hin..
Wärst du so freundlich mir eine kurze Anleitung zu schreiben, wenn du am Rechner sitzt? Wäre dir sehr dankbar.Prinzipiell auch an alle anderen danke, für die große Beteiligung an meiner Frage
Liebe Grüße
Habe an sowas gedacht:
Bitte melden Sie sich an, um diesen Anhang zu sehen.
Bitte melden Sie sich an, um diesen Anhang zu sehen.
-
Mach ne neue Funktion in der Character Klasse, also in char.h definieren.
Je nachdem was für Mengen du erwartest mach da ein int oder long long Datentyp als return value.
DIe Funktion rufst du dann überall da auf wo du bis jetzt deine Variable amount benutzt.
Es wird sich da nur das Level des Spielers genommen und mit 10 Multipliziert. Ein Level 100 Spieler zahlt also 1000 Gold pro Pull, ein Level 10 Spieler 100.
Bin nur am Handy unterwegs, was die Funktionsdefinition angeht musst du das mal ausprobieren und ggf. noch korrigieren