This is a read only copy without any forum functionality of the old Modcraft forum.
If there is anything that you would like to have removed, message me on Discord via Kaev#5208.
Big thanks to Alastor for making this copy!

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Grymskvll

Pages: 1 2 [3] 4 5
31
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 10, 2016, 12:05:01 am »
Quote from: "Nupper"
Additional Known Issues

Welcome message displays Heroic

Code: [Select]
Welcome to [Dungeon name] (5 Player (Heroic)). Instance locks are scheduled to expire in [Time Remaining]instead of
Code: [Select]
Welcome to [Dungeon name] (5 Player (Epic)). Instance locks are scheduled to expire in [Time Remaining]

You need to change the last field in MapDifficulty.dbc to "DUNGEON_DIFFICULTY_5PLAYER_EPIC"


Edit: Oh, I get it! Sorry, I completely misinterpreted an earlier post. So to fix invisible portals, see this post: http://modcraft.io/viewtopic.php?p=56547#p56547 (it refers to the mysql world.gameobject_template table)

32
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 09, 2016, 11:02:23 pm »
Quote from: "Nupper"

Gameobject_Template
Code: [Select]
GAMEOBJECT_TYPE_DUNGEONDIFFICULTY = 31

    data0: mapID (From Map.dbc)
    data1: difficulty

     

     

0 5 man normal, 10 man normal
1 5 man heroic, 25 normal
2 5 Man Epic (Possibily), 10 man heroic
3 25 man heroic


Sorry, I copied the wrong line. I updated my post to fix it.

33
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 09, 2016, 10:36:22 pm »
To fix gameobjects, you need to set the spawnMask just like we did with creatures:
Code: [Select]
UPDATE world.gameobject SET spawnMask=15 WHERE map=[map ID];

For some reason, the maxplayers and difficultystring values in MapDifficulty.dbc don't get checked for newly created rows, and I can't figure out why. I'm guessing there's something missing in Map.dbc or something. I made a hacky workaround by hooking GetInstanceInfo(). It'll work for 5 man Epic dungeons.

Also I kind of completely neglected Epic raids. Unfortunately, Epic raids would need some more in-depth modding, since in world.creature_template, difficulty_entry_# only goes up to 3, meaning you can have up to 4 difficulty versions including the base. All 4 of these versions are already used by raids for N10, N25, H10 and H25. It could be as simple as adding more columns to the table, I don't know. Other than that you'd need to add another Eluna method (SetRaidDifficulty), get some AIO communication akin to the one I wrote for SetDungeonDifficulty, and add some extra conditions in the hooked GetInstanceInfo() to check for raid and difficulty so that maxplayers and difficultystring returned by it are correct, maybe mess with some core constants, add the necessary client strings, mess with the minimap indicator (more on that below).

Also, for some reason MiniMapInstanceDifficulty_OnEvent can't be overwritten in an AIO script properly. The modified version will just exist side by side with the original, and events will call the original instead of our modified version. That's not a huge problem, since you can just supply a modified Minimap.lua (where the function resides) in a custom patch, which would be necessary if you want Epic difficulty to have a different minimap indicator blp anyway. Speaking of which, I made an Epic difficulty instance banner, it's included in the patch below, along with a modified Minimap.lua

Preview (new epic banner on the right):


Looking at the banner now, I probably should've reduced the emblem's alpha a tiny bit. Oh well! The attached file also contains the Photoshop document for that image, as well as an updated AIO script.

So right now the issues are:
-invisible instance portal when you select Epic dungeon difficulty (no idea how this works)
-no Epic raid support
-hacky GetInstanceInfo() mod instead of properly loading maxplayers and the difficultystring from MapDifficulty.dbc

Mirror: https://a.fluntcaps.me/nywray.zip

34
Did you mess with TalentTab.dbc, Talent.dbc, SkillLine.dbc, SkillLineAbility.dbc and SkillRaceClassInfo.dbc yet?

You probably also need to add entries in the world.playercreateinfo_skills mysql database, so that newly created characters learn the SkillLine for that talent tree upon creation.

35
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 08, 2016, 11:46:07 pm »
Quote from: "Grymskvll"
What's the sane way to copy over all monster spawns from a normal dungeon? From what I understand, they're stored in world.creature

In world.creature, the spawnMask column determines which difficulties a creature will spawn on. So if you want to make every creature in a Map spawn for every difficulty, you can just set the spawnMask to 15 ("Spawned in all versions of maps").

To set this spawnMask for all creatures in a specific map, you can use this mysql statement (AT YOUR OWN RISK):
Code: [Select]
UPDATE world.creature SET spawnMask=15 WHERE map=[map ID];
Replace [map ID] with the map you want to change. You still need to add Epic difficulty entries for each creature_template in the dungeon. Otherwise it uses the heroic or normal version as fallback.

As far as I know, that leaves just two imperfections:
-the dungeon portal becomes invisible when you set difficulty to to Epic. If anyone has an idea how the game picks its instance portal models, please let me know
-the little dungeon difficulty indicator when you're inside a dungeon (in the top-right, next to the minimap) just displays "0". Odds are there's no blp for an Epic difficulty (like the skull flag for Heroic), so you probably need to do some interface modding, which wouldn't be an issue since you need to use an AIO script to make the difficulty selection menu work anyway. I'm a little dismayed that I couldn't even get the indicator to show "5", though, even with a modified client-side MapDifficulty.dbc
-game objects don't seem to be spawning, gotta figure out how that stuff works (like the web door in Azjol-Nerub)

36
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 08, 2016, 11:11:48 pm »
Holy shit, all the above DOES work, I just made the mistake of thinking that the server would spawn the Epic versions of creatures if there are Epic entries in world.creature_template, which is NOT the case! But the world.creature_template IS needed for automatically spawning the right version. What I did was enter an Epic instance, used ".npc add [NORMAL world.creature_template entry]", and the server automatically grabs the Epic version (referenced in "difficulty_entry_3" of the normal version of the creature_template).

What's the sane way to copy over all monster spawns from a normal dungeon? From what I understand, they're stored in world.creature

37
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 08, 2016, 03:15:00 am »
I'm stuck. I've managed to set dungeon difficulty to Epic from the interface and create an empty Epic difficulty instance, but I can't figure out how to spawn creatures. The earliest function I can find that's called when instance creatures are spawned is Creature::LoadCreatureFromDB, but none of the places that call that function are called when you create a dungeon instance... So what the hell is calling Creature::LoadCreatureFromDB???

If you want to try debugging, here's what I did to enable the Epic dungeon difficulty:

Look up the Map entry you want to have an Epic difficulty in Map.dbc, then in MapDifficulty.dbc, create a new entry for your Map ID with the difficulty field set to 2 (Epic).

This step wont work since there's something missing, but it will be required if someone figures it out. In your mysql world.creature_template, copy entries for all the heroic versions for creatures in that Map, but change the name to have a "(2)" at the end, just like how heroic versions have "(1)".
Make sure the new Epic entries you make have nothing in the "difficulty_entry_#" fields.
In all the normal mode entries in creature_template, add a reference to the new entry you made in difficulty_entry_2

In WorldSession.h, add this below "void HandleSetDungeonDifficultyOpcode(WorldPacket& recvData);":
Code: [Select]
void HandleSetDungeonDifficulty(Difficulty mode);

In MiscHandler.cpp, add:
Code: [Select]
void WorldSession::HandleSetDungeonDifficulty(Difficulty mode)
{
TC_LOG_DEBUG("network", "MSG_SET_DUNGEON_DIFFICULTY");

if (mode >= MAX_DUNGEON_DIFFICULTY)
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUID().GetCounter(), mode);
return;
}

if (Difficulty(mode) == _player->GetDungeonDifficulty())
return;

// cannot reset while in an instance
Map* map = _player->FindMap();
if (map && map->IsDungeon())
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, GUID: %u) tried to reset the instance while player is inside!",
_player->GetName().c_str(), _player->GetGUID().GetCounter());
return;
}

Group* group = _player->GetGroup();
if (group)
{
if (group->IsLeader(_player->GetGUID()))
{
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* groupGuy = itr->GetSource();
if (!groupGuy)
continue;

if (!groupGuy->IsInMap(groupGuy))
return;

if (groupGuy->GetMap()->IsNonRaidDungeon())
{
TC_LOG_DEBUG("network", "WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while group member (Name: %s, GUID: %u) is inside!",
_player->GetGUID().GetCounter(), groupGuy->GetName().c_str(), groupGuy->GetGUID().GetCounter());
return;
}
}
// the difficulty is set even if the instances can't be reset
//_player->SendDungeonDifficulty(true);
group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player);
group->SetDungeonDifficulty(Difficulty(mode));
}
}
else
{
_player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false);
_player->SetDungeonDifficulty(Difficulty(mode));
}
}

In Eluna's PlayerMethods.h, add:
Code: [Select]
/**
* Sets the [Player]s dungeon difficulty to the specified value
*
* @param uint32 difficulty
*/
int SetDungeonDifficulty(Eluna* /*E*/, lua_State* L, Player* player)
{
Difficulty difficulty = (Difficulty)Eluna::CHECKVAL<uint32>(L, 2, 0);

WorldSession* session = player->GetSession();
session->HandleSetDungeonDifficulty(difficulty);

bool isInGroup = (player->GetGroup() != 0);
player->SendDungeonDifficulty(isInGroup);

return 0;
}

In Eluna's LuaFunctions.cpp, in "ElunaRegister<Player> PlayerMethods[]" add:
Code: [Select]
{ "SetDungeonDifficulty", &LuaPlayer::SetDungeonDifficulty },

And add this AIO script to your server's lua_scripts folder:
Code: [Select]
local AIO = AIO or require("AIO")
AIO.AddAddon()

if AIO.IsServer() then
-- TrinityCore: starting from 0=normal, 1=heroic, 2=epic
local MAX_DUNGEON_DIFFICULTY = 3

function HandlePlayerSetDungeonDifficulty(player, msg)
-- difficulties start at 0 in TrinityCore, 1 in client
msg = tonumber(msg) - 1
if msg >= 0 and msg < MAX_DUNGEON_DIFFICULTY then
player:SetDungeonDifficulty(msg)
end
end
AIO.RegisterEvent("SetDungeonDifficulty", HandlePlayerSetDungeonDifficulty)

return
end


UnitPopupButtons["DUNGEON_DIFFICULTY3"] = { text = DUNGEON_DIFFICULTY3, dist = 0 };
UnitPopupMenus["DUNGEON_DIFFICULTY"] = { "DUNGEON_DIFFICULTY1", "DUNGEON_DIFFICULTY2", "DUNGEON_DIFFICULTY3" };
DUNGEON_DIFFICULTY_5PLAYER_EPIC = "5 Player (Epic)";

function SetDungeonDifficultyCustom(difficulty)
AIO.Msg():Add("SetDungeonDifficulty", difficulty):Send()
end


origSetDungeonDifficulty = SetDungeonDifficulty
SetDungeonDifficulty = function(...)
local difficulty = ...
if difficulty < 3 then
origSetDungeonDifficulty(difficulty)
else
SetDungeonDifficultyCustom(difficulty)
end
end

Apologies if there's any errors, I made some last minute changes as I was copying the code.

Edit: forgot to mention that if you want to try to add a new difficulty, you should try to add a heroic mode to a dungeon that normally doesn't have one first. That doesn't (or at least shouldn't) require the core mods and AIO script above, it should only require mysql database and DBC edits as far as I understand, but I can't even get that to work.

38
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 07, 2016, 05:56:00 pm »
Quote from: "Grymskvll"
You'll also need to increment the MAX_DUNGEON_DIFFICULTY constant. Not sure what else you'd need.

Oops nevermind that, it's not needed at all.

I tried adding an Eluna playermethod for setting dungeon difficulty (so that the button would work), and it worked... but with a major flaw. The client's difficulty doesn't get updated until you relog. I guess you would either have to send some kind of difficulty mode update from the server to the client, or else modify Wow.exe so that it accepts 3 as a valid SetDungeonDifficulty setting.

Edit: oops, just realized that the core has Player::SendDungeonDifficulty built in. After all, it has to update group members' dungeon difficulty when the party leader sets it.

39
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 07, 2016, 03:48:11 am »
Quote from: "schlumpf"
https://wowdev.wiki/DB/Difficulty?

On that note, I guess you'd have to add epic difficulty entries in MapDifficulty.dbc.

From what I gather, TrinityCore gets creature stats from the world.creature_template database. I'm guessing that you would put a reference to an epic difficulty version of the creature in difficulty_entry_2 of the normal mode creature entry. At least, that's how it's done for raids.

So you would need to create new epic version entries in creature_template for each creature in each dungeon that you want to have an epic difficulty setting, and then reference those new epic versions in difficulty_entry_2 of the normal version.

Of course, that's not all you'd need to do to make the difficulty work.

40
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 06, 2016, 11:40:33 pm »
Right, but if you wanted to make the button work, you would need to add a way to send the request to change the difficulty (using AIO, probably).

I don't know how dungeon difficulties themselves are implemented.

41
Miscellaneous / Re: [QUESTION:Wrath]  New Dungeon Difficulty
« on: August 06, 2016, 11:21:22 pm »
In worldserver.conf, I enabled network debug logging by setting this value:
Code: [Select]
Logger.network=2,Console Server
With this, any time the server runs WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket& recvData) (in gameHandlersMiscHandlers.cpp), it prints some debug info in the worldserver console. Then I used /run SetDungeonDifficulty(#). It worked for values of 1 and 2 (normal and heroic), but it didn't seem to send anything to the server with a difficulty value of 3.

That means you probably need to use AIO to send a request to set dungeon difficulty to 3. Hopefully you don't need to otherwise mess with the client to fix the unused difficulty. TrinityCore should be able to set your difficulty to 3 if it receives the request. You'll also need to increment the MAX_DUNGEON_DIFFICULTY constant. Not sure what else you'd need.

42
Nice. Any chance of a video? For the two capture-points that give a buff, is the buff temporary? I imagine it could lead to snowballing otherwise.

43
Miscellaneous / [LUA] Modifying secure variables without taint
« on: August 03, 2016, 08:27:59 pm »
If there's a better solution, or if there are any improvements to be made to this, please let me know.

I was working on a custom secondary class resource system (demo here: ) and ran into the phenomenon of interface taint (more info here: http://wowwiki.wikia.com/wiki/Secure_Ex ... d_Tainting).

From what I understand, normally when you're modding the interface for addons, you don't necessarily need to directly change the return value of API functions. However, I needed to change the return value of certain secure functions based on custom conditions (like checking custom resource values to see if a spell is usable).

The problem is that directly changing secure functions will taint them, causing interface errors (or at least it causes ugly notifications to be printed in the chat window). The good news is there's apparently a way to modify secure variables (including functions).

Here's how:


1) Requires a patched Wow.exe to load modified interface files (see http://www.ownedcore.com/forums/world-o ... mover.html).

2) Find the most up-to-date FrameXML.toc (GlueXML.toc should work too) in your client. For the standard WotLK 3.3.5 version, it should be in [your-WoW-folder]Data[locale]patch-[locale]-3.MPQ
Full path:
InterfaceFrameXMLFrameXML.toc

3) Extract FrameXML.toc to [your-WoW-folder]InterfaceFrameXML, or make a new MPQ for it. Either should work.

4) Open it up in any text editor and add this new line at the bottom (the path and filename are arbitrary, change it if you feel like it):
Code: [Select]
..CustomSecureVarsCustomSecureVars.lua
5) Create a new folder in [your-WoW-folder]Interface, name it CustomSecureVars. In the new folder, create a text file called CustomSecureVars.lua. This file will hold all the new secure variables you need. Feel free to edit secure functions all you want, they'll still be secure so long as you don't taint them by accessing any tainted variables.

Top tips for keeping variables secure:


If you want to call a (potentially) tainted function, use the "securecall" API function (see http://wowwiki.wikia.com/wiki/API_securecall).

If you need to provide a tainted variable as an argument from a modified secure function, provide it as a string and have the called function resolve the string to a global variable. That way the secure function stays secure, and only the called function needs to deal with taint.

For debugging, you can check individual variables with "issecurevariable" (see http://wowwiki.wikia.com/wiki/API_issecurevariable)

You can also enable taint logging (http://wow.gamepedia.com/CVar_taintLog). Any time your chat window shows "Interface action failed because of an AddOn", it'll write a report in WoWLogstaint.log. Remember to delete your taint.log in between tests for convenience! And remember to turn off logging after your tests!

I don't always get an interface error when accessing a tainted variable from a secure function, I'm not entirely sure how it works. Specific lines of code seem consistent, but different modifications don't always cause an error.

Example:


Lets say you have a tainted variable:
Code: [Select]
TaintedVar = "hi I'm a tainted variable"
You can't keep it secure because it's managed by an AIO script or addon. You also want to check TaintedVar inside the secure GetShapeshiftFormInfo API function, so you hook it:
Code: [Select]
local origGetShapeshiftFormInfo = GetShapeshiftFormInfo;
GetShapeshiftFormInfo = function(...)
local texture, name, isActive, isCastable = origGetShapeshiftFormInfo(...)

if (TaintedVar) then print(TaintedVar) end -- oops, we're accessing a tainted variable!

return texture, name, isActive, isCastable
end

Testing this on a character with a shapeshift/stances bar, I get "Interface action failed because of an AddOn" during combat. The solution is to make a new function that's allowed to get tainted (because it's not used by the official UI), the new function will return the tainted value we want to check. We'll call the new function using securecall, providing the name of the tainted value we want to check.

Code: [Select]
local function GetTaintedVar(varname)
-- _G[variable name] retrieves a global variable
return _G[varname]
end

local origGetShapeshiftFormInfo = GetShapeshiftFormInfo;
GetShapeshiftFormInfo = function(...)
local texture, name, isActive, isCastable = origGetShapeshiftFormInfo(...)

-- Even if GetTaintedVar is tainted, secure status is restored after the call
local SecureVar = securecall(GetTaintedVar, "TaintedVar")
if (SecureVar) then print(SecureVar) end

return texture, name, isActive, isCastable
end

The key here is that the function that has to stay secure (GetShapeshiftFormInfo) doesn't access any tainted variables, except the GetTaintedVar function, which it provides as an argument for securecall, but thanks to the magic of securecall, secure status is restored after the call to securecall. TaintedVar is just provided as a variable name string, and then checked by the function that we're allowing to get tainted. It seems that the function being called by securecall is allowed to be tainted, but not any arguments provided along with it, thus the need to provide the name of the variable as a string.

44
Quote from: "schlumpf"
Please always prefer to use specialized packets: They are localized. Keeping semantics help for good user experience. There have been a lot of english-only errors in emulators for various things (summoning pets, buying stuff, …) in the past which could just be avoided by sending the correct packet.

Ah yeah, good point. In that case I guess a new Player:SendBuyError Eluna method would be preferable, so that you don't hardcode a specific BuyError in the event trigger.

In the case of the custom rep check, you could have the script send BuyResult BUY_ERR_REPUTATION_REQUIRE. If there's no BuyResult that suits your purpose, maybe you could have the script resort to checking the player's locale with (Eluna's) Player:GetDbLocaleIndex or Player:GetDbcLocale and use Player:SendNotification with a localized string.

Edit:
Here's how the locales are defined in TrinityCore's Common.h (and returned by Eluna's player methods above):
Code: [Select]
enum LocaleConstant
{
    LOCALE_enUS = 0,
    LOCALE_koKR = 1,
    LOCALE_frFR = 2,
    LOCALE_deDE = 3,
    LOCALE_zhCN = 4,
    LOCALE_zhTW = 5,
    LOCALE_esES = 6,
    LOCALE_esMX = 7,
    LOCALE_ruRU = 8,

    TOTAL_LOCALES
};

45
If I'm not mistaken, you'd want to trigger the event from TrinityCore's Player::BuyItemFromVendorSlot. Instead of using SendBuyError, you could just use Eluna's Player:SendNotification method to show the player the red error text (or add a Player:SendBuyError method to Eluna if you really want to, but from what I understand its only purpose is to show the error message).

I'm not sure if it really matters where in Player::BuyItemFromVendorSlot you trigger the event. I'd personally put it above all the other checks, since the custom condition is probably less trivial than something like a gold check.

The event trigger (inside Player::BuyItemFromVendorSlot) should look something like this. The arguments are just the player ("this" refers to the player since it's a player method), followed by all the parameters of Player::BuyItemFromVendorSlot (in case any script wants to use any of it):
Code: [Select]
// Run all event handlers. If any of them return false then...
if (!sEluna->OnBuyFromVendor(this, vendorguid, vendorslot, item, count, bag, slot))
{
// ...abort the purchase!
return false;
}

Just for clarity, OnBuyFromVendor doesn't exist (yet). You'd have to add/request it.

Like Kaev said, you can just look at existing hooks to see how to implement a new one. Be sure to look at hooks that can return false, since you want to be able to abort the purchase.

Pages: 1 2 [3] 4 5