Jump to content
metin2dev

OtherChoice

Member
  • Content Count

    27
  • Joined

  • Last visited

Community Reputation

4 Neutral

About OtherChoice

  • Rank
    Neutral

Profile Information

  • Gender
    Not Telling

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. OtherChoice

    open Official logout method

    Uhm at first i would say you should remove it from HEADER_CG_CHAT HEADER_CG_WHISPER and try again, if this is not the problem it will need some deeper debugging
  2. OtherChoice

    open Official logout method

    Honestly i do not know why timed_event_cancel has no declaration however just go in game/battle.h, find extern void battle_end(LPCHARACTER ch); and add below extern bool timed_event_cancel(LPCHARACTER ch); then check game/battle.cpp should contain this function bool timed_event_cancel(LPCHARACTER ch) { if (ch->m_pkTimedEvent) { event_cancel(&ch->m_pkTimedEvent); return true; } return false; } Now you should not have any compiling error. Next you asked about packets: input_main.cpp handles packets with HEADER_CG (CG == client to game) in function int CInputMain::Analyze(LPDESC d, BYTE bHeader, const char * c_pData). Packets with HEADER_GC (GC == game to client) are instead handled by the client itself but according to the phase the client is in (eg. phaseGame, phaseSelect...). phaseGame packets (which are most probably what are you looking for) are recived in Userinterface/PythonNetworkStreamPhaseGame.cpp in void CPythonNetworkStream::GamePhase(). Other Client Packet Reciever And lastly there are some HEADER_GD packets which are game to database handled by db binary.
  3. OtherChoice

    open Official logout method

    If you won't succed on your own just let us know what are you exactly trying to accomplish, gl
  4. OtherChoice

    open Official logout method

    This is not how official logout works: in game/battle.cpp you have a function bool timed_event_cancel(LPCHARACTER ch) which checks whether the argument (LPCHARACTER ch) is logging off or not, if so it will cancel the timed event and return true. This function is called in int battle_melee_attack (LPCHARACTER ch, LPCHARACTER victim) on both victim and attacker and on a true (stopped logout attempt) will send chat_packet "the battle has begun..." If you want to stop logout on a custom defined action you can simply call timed_event_cancel(ch).
  5. OtherChoice

    open Item sell price bug

    Check those things : 1) item_proto table (serverside either txt or sql) and item_proto (client side) prices matches 2) In PythonPlayerModule.cpp in PyObject * playerGetSellItemPrice(PyObject * poSelf, PyObject * poArgs) there's a line: iPrice /= 5; and the same exact value should be set in shop_manager.cpp (server source/game) in void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount) like this: dwPrice /= 5; (If any of those two is missing or has a different value make sure to correct it).
  6. OtherChoice

    open [Clientside] How to get real stats

    Ok after testing the original bugfix you linked i found the problem, the m_akSimplePlayerInfo array is filled in a wrong way this is the solution: In game/char.cpp at void CHARACTER::PointsPacket() change as following void CHARACTER::PointsPacket() { if (!GetDesc()) return; TPacketGCPoints pack; pack.header = HEADER_GC_CHARACTER_POINTS; pack.points[POINT_LEVEL] = GetLevel(); pack.points[POINT_EXP] = GetExp(); pack.points[POINT_NEXT_EXP] = GetNextExp(); pack.points[POINT_HP] = GetHP(); pack.points[POINT_MAX_HP] = GetMaxHP(); pack.points[POINT_SP] = GetSP(); pack.points[POINT_MAX_SP] = GetMaxSP(); pack.points[POINT_GOLD] = GetGold(); pack.points[POINT_STAMINA] = GetStamina(); pack.points[POINT_MAX_STAMINA] = GetMaxStamina(); for (int i = POINT_ST; i < POINT_IQ + 1; ++i) pack.points[i] = GetRealPoint(i); for (int i = POINT_IQ + 1; i < POINT_MAX_NUM; ++i) pack.points[i] = GetPoint(i); GetDesc()->Packet(&pack, sizeof(TPacketGCPoints)); } then at void CHARACTER::Disconnect add this line if (GetDesc()) { /*add this*/ PointsPacket(); /* */ packet_point_change pack; pack.header = HEADER_GC_CHARACTER_POINT_CHANGE; pack.dwVID = m_vid; pack.type = POINT_PLAYTIME; pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000; pack.amount = 0; GetDesc()->Packet(&pack, sizeof(struct packet_point_change)); GetDesc()->BindCharacter(NULL); // BindDesc(NULL); } then in client source PythonNetworkStreamPhaseGame.cpp -> bool CPythonNetworkStream::RecvPointChange() ------->Make these changes case POINT_PLAYTIME: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].dwPlayMinutes = PointChange.value; break; case POINT_LEVEL: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointChange.value; __RefreshStatus(); __RefreshSkillWindow(); break; /*case POINT_ST: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointChange.value; __RefreshStatus(); __RefreshSkillWindow(); break; case POINT_DX: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointChange.value; __RefreshStatus(); __RefreshSkillWindow(); break; case POINT_HT: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointChange.value; __RefreshStatus(); __RefreshSkillWindow(); break; case POINT_IQ: m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointChange.value; __RefreshStatus(); __RefreshSkillWindow(); break;*/ case POINT_ST: case POINT_DX: case POINT_HT: case POINT_IQ: __RefreshStatus(); __RefreshSkillWindow(); break; Every other thing is like original thread Tested and working.
  7. OtherChoice

    open [Clientside] How to get real stats

    Oh ok i quite didn't get it, anyhow that's the solution you are looking for This is you void CHARACTER::Disconnect(...) //ADD this PointChange(POINT_ST, 0); PointChange(POINT_DX, 0); PointChange(POINT_IQ, 0); PointChange(POINT_HT, 0); //end packet_point_change pack; pack.header = HEADER_GC_CHARACTER_POINT_CHANGE; pack.dwVID = m_vid; pack.type = POINT_PLAYTIME; pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000; pack.amount = 0; pack.point_ST = GetPoint(POINT_ST); pack.point_DX = GetPoint(POINT_DX); pack.point_HT = GetPoint(POINT_HT); pack.point_IQ = GetPoint(POINT_IQ); GetDesc()->Packet(&pack, sizeof(struct packet_point_change)); /*if (GetHorseST() > GetPoint(POINT_ST)) PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST)); if (GetHorseDX() > GetPoint(POINT_DX)) PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX)); REMOVE ALL THIS if (GetHorseHT() > GetPoint(POINT_HT)) PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT)); if (GetHorseIQ() > GetPoint(POINT_IQ)) PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ));*/
  8. OtherChoice

    open [Clientside] How to get real stats

    The way you are trying to work with won't go anywhere, first, the point you are packing are in a wrong place, since the first time ComputePoints() is exectuted it will check whether your horse has higher stats than yours and then replace them if so and will however pack and send them to client. If you want to make sure you have your real stat points you need to create the packet inside CHARACTER::ComputePoints() function not in void CHARACTER::Disconnect. Next point is the packet you are using: since packet_point_change (HEADER_GC_CHARACTER_POINT_CHANGE) has already a defined behavior (it has 3 different behavior actually, in PhaseGame, PhaseSelect and PhaseLoading) i suggest you to avoid using it. Moreover if your goal is to always show base stats and hide horse bonuses, you can skip the whole client part and do in a simpler way. I will first explain how to get both base Stats and horse Stats. ____________________________________________________________________________________________________ If you want to totally hide horse stats you can do something like this: Done.
  9. OtherChoice

    open [Clientside] How to get real stats

    In Server source game/char.cpp in ComputePoints() if (IsPC()) { if (GetMountVnum()) { if (GetHorseST() > GetPoint(POINT_ST)) PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST)); if (GetHorseDX() > GetPoint(POINT_DX)) PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX)); if (GetHorseHT() > GetPoint(POINT_HT)) PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT)); if (GetHorseIQ() > GetPoint(POINT_IQ)) PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ)); } } This way horse stats will override lower stats. Those numbers are then packeted and sent to client. You could create a new packet sending base stats to client. To recive base stats from game use game/char.cpp int CHARACTER::GetPoint(type) where type is POINT_ST, POINT_DX, POINT_HT, POINT_IQ example: game/packet.h && UserInterface/packet.h enum { HEADER_CG_HANDSHAKE = 0xdc, .... HEADER_GC_BASE_STATS = (your_value), typedef struct base_stats { BYTE header; DWORD point_ST; DWORD point_DX; DWORD point_HT; DWORD point_IQ; } TPacketGCBaseStats; then send this packet from somewhere: if (IsPC()) { if (GetMountVnum()) { TPacketGCBaseStats pack; pack.header = HEADER_GC_BASE_STATS; pack.point_ST = GetPoint(POINT_ST); pack.point_DX = GetPoint(POINT_DX); pack.point_HT = GetPoint(POINT_HT); pack.point_IQ = GetPoint(POINT_IQ); ch->GetDesc()->Packet(&pack, sizeof(pack)); if (GetHorseST() > GetPoint(POINT_ST)) PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST)); if (GetHorseDX() > GetPoint(POINT_DX)) PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX)); if (GetHorseHT() > GetPoint(POINT_HT)) PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT)); if (GetHorseIQ() > GetPoint(POINT_IQ)) PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ)); } And then recive it from client and do whatever you like with those. REMEMBER to declare both the packet header and the typedef struct inside packet.h of client binary as well.
  10. OtherChoice

    open Default mount system [BUG]

    There are a lots of input which results in riding/dismount mounts so there is a wide variety of possible reasons. The only thing i can suggest you is to check GetMountVnum() function and its occurencies inside your server game source.
  11. OtherChoice

    open Bug Sash System

    I don't actually know how sash system is made but if it uses packet to tell client when to execute sash stuff (effect and model) you may want to add a new packet in server source game/item.cpp: bool CHARACTER::UnequipItem(LPITEM item) and check for item->GetVnum() == Sash_vnums (use CItemVnumHelper::Your_Function or anything that fits your needs)
  12. OtherChoice

    open Fishing rod - how to add effect?

    What you are looking for is a quite composite task. Basically you can declare the effect inside playersettingmodule.py like this: chrmgr.RegisterCacheEffect(chrmgr.EFFECT_DUST, "", "d:/ymir work/effect/etc/dust/dust.mse") chrmgr.RegisterCacheEffect(chrmgr.EFFECT_HORSE_DUST, "", "d:/ymir work/effect/etc/dust/running_dust.mse") chrmgr.RegisterCacheEffect(chrmgr.EFFECT_HIT, "", "d:/ymir work/effect/hit/blow_1/blow_1_low.mse") chrmgr.RegisterCacheEffect(chrmgr.EFFECT_FISHING_ROD, "Bip01 R Hand", "d:/ymir work/effect/fishing_rod/fishing_effect.mse") #Bip01 R Hand is the standard hand bone, you can anyway attach it to every bone you desire then declare EFFECT_FISHING_ROD in InstanceBase.h in the effect enum and in PythonCharacterManagerModule.cpp add PyModule_AddIntConstant(poModule, "EFFECT_FISHING_ROD", CInstanceBase::EFFECT_FISHING_ROD); And then in InstanceBase.cpp in function: UINT CInstanceBase::__GetRefinedEffect(CItemData* pItem) { DWORD refine = max(pItem->GetRefine() + pItem->GetSocketCount(),CItemData::ITEM_SOCKET_MAX_NUM) - CItemData::ITEM_SOCKET_MAX_NUM; switch (pItem->GetType()) { case CItemData::ITEM_TYPE_WEAPON: ..... case CItemData::ITEM_TYPE_ARMOR: ..... /*add->*/ case CItemData::ITEM_TYPE_ROD: if (any_condition_you_desire) __AttachEffect(EFFECT_FISHING_ROD); Anyway this is a very rough example beacuse i do not have enough information about the condition needed for this effect to show. Be careful: If you want to perform a serverside check of any type before applying this effect you might need to setup a packet work-around.
  13. OtherChoice

    open Some questions about LUA functions

    Sorry mate but for the sake of a clean and readable code you should change this To something like this: If number(0,(denominator-1)) <= (numerator-1) where your chance is: numerator/denominator Lets say you want a 10% droprate so 1/10 chance: If number(0,9) <= 0 then or a 0,03% droprate == 3/10000 you will use: If number(0,9999) <= 2 then The best suggestion i can give you is to make a function inside your game source to call anytime you want to output a result of a chance: int game_rnd_chance(lua_State * L) { if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { lua_pushboolean(L, false); } if (number(0,(int)lua_tonumber(L, 2)-1) <= (int)lua_tonumber(L,1)-1) lua_pushboolean(L, true); else lua_pushboolean(L, false); return 0; } void RegisterGameFunctionTable() { luaL_reg game_functions[] = { ..... { "rnd_chance", game_rnd_chance }, } } and then call it like this: if game.rnd_chance(numerator, denominator) == true then Anyway if you still want to stick with the code you wrote i suggest you to at least remove the redundant part: if number(1,100) > (100 - drop_chance) then // --> to --> // if number(1,100) <= (drop_chance) then
  14. OtherChoice

    open Some questions about LUA functions

    On ServerSide source files in questlua_game.cpp the function is defined like this: int game_drop_item_with_ownership(lua_State* L) { LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPITEM item = NULL; switch (lua_gettop(L)) { case 1: item = ITEM_MANAGER::instance().CreateItem((DWORD) lua_tonumber(L, 1)); break; case 2: case 3: item = ITEM_MANAGER::instance().CreateItem((DWORD) lua_tonumber(L, 1), (int) lua_tonumber(L, 2)); break; default: return 0; } if ( item == NULL ) { return 0; } if (lua_isnumber(L, 3)) { int sec = (int) lua_tonumber(L, 3); if (sec <= 0) { item->SetOwnership( ch ); } else { item->SetOwnership( ch, sec ); } } else item->SetOwnership( ch ); PIXEL_POSITION pos; pos.x = ch->GetX() + number(-200, 200); pos.y = ch->GetY() + number(-200, 200); item->AddToGround(ch->GetMapIndex(), pos); item->StartDestroyEvent(); return 0; } So the function you are trying to call is already accepting a second and a third parameter for quantity and ownership duration. You could simply use game.drop_item_with_ownership(item_vnum, item_quantity, ownership_duration) The StartDestroyEvent() function has a default value of sec = 300 defined in item.h but you can enter the time you desire as a parameter: item->StartDestroyEvent(time_you_desire);
×