Go Back   EQEmulator Home > EQEmulator Forums > General > General::Server Discussion

General::Server Discussion Discussion about emulator servers.
Do not post support topics here.

Reply
 
Thread Tools Display Modes
  #1  
Old 04-08-2025, 10:42 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Talking [Project Moth]

Salutations my fellow Norrathians.

I am announcing today my new project, codenamed "Moth" - an EverQuest passion project. I've played since I was 10, and quit LIVE / Progression Servers about 9 times after pulling several server firsts with your usual poopsockers. I spent a few years as a guide, played on lots of different eqemu servers and it was my first step into the larger game industry that is today.

All in all, EQ is in my bloodstream - but there was something I always wanted and that was to reach into Norrath like a mad god and turn it on it's head.

Project Moth will be just that. As a passion project, I am using this game as a sandbox to learn LUA and SQL more intimately.

The goals I have in mind (just to name a few for now):

- To take the concepts of Planes of Power flag progression and tie that to gameplay in earlier expansions in a fun way while players level, offering new quests and rewards for slaying nostalgic zone bosses like Emperor Crush, The Ghoul Lord, or King Xorbb, etc, etc, so on, so forth.

- To unlock and unravel the mysteries of race / class mixes and allow players to play in ways they want to play. (And if the server is full of Ogre Monks, so be it!)

- To push the bleeding limits of what can be developed, design new zones, new challenges and new gameplay never experienced on an EverQuest server while remaining (in part) true to the roots of Norrath adventure that was established long ago.

Everything is very much in early stages - so a lot needs to be done.
I hope the server will grow with time and people will try it out.

For anyone interested in the project, you can jump in early - but expect at least one server reset once firm decisions come into the picture.

Right now it is Classic Locked, testing and development are pretty much myself. If you are an active player looking to contribute their EQ knowledge to the server, find quest bugs and whatnots to be fixed, I welcome you and your input.

Thanks, and hope to see you online!
Reply With Quote
  #2  
Old 04-09-2025, 12:15 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/9/2025)

- Titanium (nope. too limited)
- SoF (nope that softlocks apparently...)
- RoF2 Client for (hopefully) least buggy at this point.

REQUIRED:

// DELETE
arena.eqg
arena_EnvironmentEmitters.txt
lavastorm.eqg
nektulos.eqg
Nektulos_EnvironmentEmitters.txt
New Highpass Zone Files

// Replace with typical P99 old zone files, including old highpass.

- Current expansion set to 0 (Classic).
- Gutted Crescent Reach / New Freeport as character starting zones out of the databases to avoid zone syncing issues. I have no intention of using these zones anytime soon, if ever.
- Set expansion_req to 0 for all class-race combinations in hopes this is a step to allowing all base race/class combinations available in Classic.
- Set World:CharacterSelectExpansionSettings to 127 (Up to Gates of Discord) - This has opened up character creation out of era from Classic for race / classes.
- Edited world/client.cpp Race/Class tables set to true for everything.

// RACIAL STARTS

Iksar in Cabalis (Pre Kunark on server, I need to create an outpost in Classic and set spawn points to that outpost)
// Added Iksar GMs in North Ro just shy of the fisherman huts.
// Added Spell Vendors in North Ro.
// Added Start Zone points for North Ro.
//BACKED UP char_create_combinations - gutted Cabalis spawn points for now so Iksar are forced to spawn in North Ro.


Vah Shir in Shar Vahl (Pre Luclin on server, I need to create an outpost in Classic and set spawn points to that outpost)
// Added BST, SHM and BER GMs by Kelethin Nexus Spires - other classes can be found in Kelethin without faction issues. (Ideal)
// Added BST and SHM Spell Vendors by Kelethin Nexus Spires
// Added Start Zone points for Vah Shir to start in Kelethin
// Shar Vahl Start Zone Points marked as 3 min, 99 max in start_zones table. Kelethin start points 0 min, 2 max. (This should make it so that when Luclin is available, it will swap to Shar Vahl by default.)
// Shar Vahl marked as 3 min, 99 max in zone table. (Just extra checks.)
// Vah Shir / Shar Vahl expansion_req set to 3, Vah Shir / Kelethin expansion_req set to 0. (Just extra checks.)
// Using SoF+ client, I can successfully get the character to start in Greater Faydark.
// BACKED UP char_create_combinations - gutted out Shar Vahl combos so that players are locked to starting in Kelethin.

Froglok in Rathe Mountains (seems OK, I wouldn't touch it.)
Reply With Quote
  #3  
Old 04-10-2025, 11:24 AM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/10/2025)

Navigating EQEmu Discord and forums, I got some useful tips to proceed with backing up the spawn locations and then gutting them out of the system. I was able to proceed to build the outposts as mentioned above in yesterday's log.

Mostly NPC work today to make sure players will have the minimum they need to survive and play in Classic as Iksar and Vah Shir. Froglok I am not worried so much about because they're cleverly placed independently in Rathe Mountains.

Once I get this done, I should look into blocking off any zoning / content that would enable players to reach Kunark or Velious or beyond. Though the server is set to Classic, I can rely on it to simply "kick" players from entering certain zones that are Out of Era.

// Iksar Outpost has "basic" needs for essential Iksar gameplay. GMs, Spell Vendors, Food Vendor, and Banker. They are established in North Ro and on the Legion of Cabilis faction.
// Scripted Zzessdrox with some lore friendly dialogue. I'll probably dig deeper into developing a questline for him later down the road.
*** I want to add some tradeskilling to this spot since Iksar rely on it a lot, but will need to look more into that later.
*** I'd love to edit the map file to add in some housing for the outpost.

// SEALED OFF Traveling to Iceclad from NRO
// Backed up Translocator's script, and removed the translocate dialogue functionality.
// #npcspawn remove on the pirate skiff to prevent boarding and swimming out to Iceclad.
***Not sure if you can just exit by swimming / levitation...

// SEALED OFF Traveling to Timorous from Oasis
// Translocator apparently wasn't spawning at all.
// Had to install XXAMP to target Barrel_Barge and #npcspawn remove it - he was a swimming human. Weird. Anyway, nobody getting to Kunark riding on his shoulders.
***Not sure if you can just exit by swimming / levitation...

// Outposts have a single Guard who is also the quest point for that outpost. (IN DEVELOPMENT)
// Added "Company Legionaire Zzessdrox" to Iksar outpost.
// Added "Guardian Rasashi" to Vah Shir outpost.
// Iksar are on Cabilis Factions.
// Vah Shir are on Shar Vahl factions. Guardian Rasashi is on Emerald Warriors explicitly to mimic Guards in the Faydark. (For some reason he wouldn't attack Crushbone Orcs.)
***Tested around with Vah Shir starting area for a bit - seems cozy compared to Iksar so far from home.

*GAMEPLAY ADJUSTMENTS (NEEDS FURTHER TESTING)*

WIZARDS
//SPELL CRIT: Wizards will get a natural 25% spell crit chance on top of a global 1% chance for everyone.
//SPELL CRIT: Wizards get a 200 Crit Ratio on top of the global 100 crit ratio for everyone.

RANGERS
//ARCHERY: Boosted to a base damage of 6, and a damage bonus of 3.
//ARCHERY: 2X Bonus level now starts at 20.
//ARCHERY: 2X Bonus requires stationary NPC
//ARCHERY: Crit Difficulty reduced from 3400 to 500
Reply With Quote
  #4  
Old 04-11-2025, 05:18 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/11/2025)

// Successfully edited LOADING / Character Select Zone entirely with old Radiant + OpenZone guide. (Tedious and buggy, the more I dug into it.)

// Awesome discussion with Xachery on voice chat regarding EQGZI, Manager and Quail to simplify the process with those tools after building a custom dinput8.dll (eq_core.dll) to inject the test zone into the game.
***EQG seems to be the way for anything new I am doing, should be no reason to continue to use sd3 files for new content - but may hit some hiccups on editting older zones.

//Setup LANTERN for Unity, giving me access to assets for building and customizing zones using already available textures and whatnots from the original trilogy.

XXXXXXXXXXX
IDEAL PROCESS

-- LANTERN + Probuilder in Unity ---> Export to FBX
Import FBX into Blender, ensure validity with materials and whatnot and SAVE.

-- Generate zone using EQGZI Manager and overwrite the prefab blender file with the previous blender imported FBX file of the same name.

-- Convert to EQG file, place in EQ directory.
-- Rebuild eq core file to include new zone.
-- Update SQL zone database with new zone information.
-- Update eqStrID with string information for the new zone.
-- Test in game, debug, etc.
XXXXXXXXXXX
Reply With Quote
  #5  
Old 04-12-2025, 12:16 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/12/2025)

Experimenting with different method of zone editing between SAGE, EQGZI and LANTERN.
SAGE = Good for quick edits to zones.
LANTERN + EQGZI may be better for custom zones. I need to spend more time poking at this.

XXXXXXXXXXXXXXXXXXXXXX
Server Edits (Experimental)

// classes.h
- Changed Class Bitmask from uint16 to uint32, allowing to exceed the bitmask limitation of 65535.
- ALL_CLASSES_BITMASK = std::numeric_limits<uint32>::max();
- Added uint8 Class ID 17 "RuneKnight"
- Added uint32 Class Bitmask "RuneKnight = 65536"
- Add uint string for class names "Rune Knight"
- Added uint8 Class ID 36 "RuneKnightGM"
- Line 147 - GetPlayerClassBit changed from uint16 to uint32

// classes.cpp
- Added Switch Case for ClassID "Rune Knight" naming conventions above level 51.
- Added Switch Case for ClassID "RuneKnightGM" for Class Guildmaster.
- Added "Rune Knight" to IsFighterClass
- Added "Rune Knight" to IsSpellFighterClass
- Added "Rune Knight" to IsHybridClass
- Added "Rune Knight" to IsHeroicINTCasterClass
- Added "Rune Knight" to IsPlateClass
- Set "!EQ::ValueWithin" to accomodate for "Rune Knight" with switch case string abbreviation "RUN"
- Set "IsPlayerClass" in "EQ:ValueWithin" to accomodate for "Rune Knight".
- Line 392 GetPlayerClassBit changed from uint16 to uint32

// client.cpp
- Line 592 - Set !EQ::ValueWithin" to accomodate for "Rune Knight". (Packets?)
- Line 2048 - Added BaseClass Stat bonuses for "Rune Knight" (5 STR, 5 STA, 10 INT, 5 CHA, 25 Points)
- Line 2069 - Added ClassRaceLookupTable for "Rune Knight" (Set all to true since this server will inevitably be ALL/ALL combos)

XXXXXXXXXXXXXXXXXXXXXX
EQ_CORE Edits (Experimental)

//EQData.h
- enum PlayerClass | RuneKnight = 17, TotalClasses = 17
- _ClassInfo Array | {1,0,0,0,0,0,0,16,"Runeknight","run"}, //run
Reply With Quote
  #6  
Old 04-14-2025, 01:09 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/13 - 4/14 2025)

I was out most of yesterday, but I poked more at SAGE and other zone edit tools with Raithel, mostly troubleshooting EQGZI type of stuff.

- So far, it seems doing anything LANTERN related for edits is a lot more convoluted.
- Raithel introduced to me his new tool EQZoneCreator that simplifies working with Quail to convert models into blend files, allowing quick edits in blender, then recompiling the quail back into EQG.
- SAGE is still troublesome - any edits I make seem to not work on S3D zones when converting to EQG - so my NRO edits will just not take. May have to wait for the S3D compatibility to finish.

So, for now, I have a few tools at my disposal for playing around with creating custom zones, but doing direct zone edits in old classic zones may have to wait further.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

- Went ahead and rebuilt server from scratch using Manual Installer, hopefully allowing me more control over compiling - I would like to use it as a dev environment that I can take and push changes over to the Spire install, but that will take some setting up.

- Apart from everything else, I'm working on building starting points for all race / class combinations that make sense.

Ex. Humans who want to be beastlords, shamans or berserkers will start in Halas. (Made the most sense.)

Ex. Dark Elf bards start in The Maiden's Fancy (and I need to build Bard GM / Vendors)
Dark Elf Beastlords and Shamans can start in Neriak because there were some GMs in the Foreign Quarter at one point - I just spawned them in for now, may just set them to non-combat to prevent city killers from going after them.

Also found some caves in Neriak Foreign Quarter to host a Monk Guild
Also found some places in Neriak Third Gate to host a Paladin Guild
Druids and Rangers, I may outpost in Nektulos exclusively near the city tunnel.
***** but yeah... lots of work to be done per race / class matchup, but hope to have that done this week.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Recompiled Server Files using Manual Install with previously mentioned adjustments to classes.cpp, classes.h and client.cpp
MERGE SUCCESSFUL

So we can now see that there are indeed entries for the adjustments on server side when we do a search for classes #find class
However, we need to adjust them in the array to make sure we're not overwriting any hidden class information.
PEQ reflects class 17 as "Banker" - so let's move Rune Knight and Rune Knight GM to classes 74 and 75, as listed on PEQ Editor.
-UPDATE- Realizing an error of my own, EQ::ValueWithin is checking class IDs between Warrior and Berserker (1 thru 16) by default. If we're using ID 74 for Rune Knight and appending the EQ:ValueWithin to check until Rune Knight, we're actually setting all classes as IsPlayerClass.

Checking the database, luckily, nothing is actually using class 17 or class 36, so we can recompile those values back to 17 and 36 respectably and we should be fine, and thus, not making every class a player class.

- Edited classes.h for Rune Knight 17 and 36.
- Added Rune Knight classes 17 and 36 to PEQ Database data.php - so that it reflects correctly on the editor and doesn't throw warnings at me. (We just want things to be clean!)
- Added to db_str in SQL - entry 36389: id 17, type 13 "Runeknights" (17^13^Runeknights^0)

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

// npc_scale_manager.cpp
- Added Switch cases in for Rune Knights (literally just a copy of Shadowknight) :: GetClassLevelDamageMod (Line 415)

// npc.cpp
- Line 4338 - Added RuneKnight to RuneKnightGM link under IsGuildMasterForClient

// mob.cpp
- Line 1011 - Added Runeknight and RuneknightGM to IsIntelligenceCasterClass switch case list.
- Line 1056 - Added Runeknight and RuneknightGM to IsWarriorClass switch case list. (I guess a lot of mobs derive from "Warrior".)
- Line 1107 - Added RuneKnight and RuneKnightGM to Hybrid Archtype switch case list.
- Line 1233 - Added RuneKnightGM to SetSpawnLastNameByClass switch case list. (Cool, all RuneKnightGMs will now automatically get that last name in parenthesis underneath them.)
- Line 1473 - Added RuneKnightGM to the "AllowCrossClassTrainers" check. (Not sure if I'll use this, but good to plug.)
- Line 4692 - Added RuneKnight to CanThisClassTripleAttack GetLevel >60 check.
- Line 5271 - Added RuneKnight to >50 SpellCastTime "good effect". (Maybe this is some kind of innate spell haste effect?)
- Line 8442 - Added Runeknight to "Plural Class" switch case list.
- Line 8766 - Added RuneKnightGM to IsGuildMaster switch case list.

//client_process.cpp
- Added inclusion for RuneKnightGM for OPGMTraining
- Added inclusion for RuneKnightGM for OPGMEndTraining
- Added inclusion for RuneKnightGM for OPGMTrainSkill

//client_mods.cpp
- Line 1072 - Added RuneKnight to gain MR calculations like WAR/BER

//lua_client.cpp + lua_client.h
- Line 155, set GetClassBitMask to expect int32 instead of int16 (May be necessary if it needs to read bitmasks beyond 65535)

//perl_client.cpp
- Line 2005 set Perl_Client_GetClassBitmask to expect uint32 instead of uint16 (May be necessary if it needs to read bitmasks beyond 65535)
Reply With Quote
  #7  
Old 04-15-2025, 04:33 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG (4/15/2025)

Slower progress today. I got through a lot yesterday, but now I feel like I'm hitting a brick wall.

THE PROBLEM:
RuneKnightGM does not kick open the Training Window


Testing RuneKnightGM with Character:AllowCrossClassTrainers (true) resulted in all class trainers not kicking open the Training Window while the character is set to 17 (RuneKnight).

Resetting it back, the trainers will kick the "You are not of X class" response - so we know they acknowledge the difference of class.

- Added a baseline copy of Level 1 Warrior Skills to the RuneKnight via skill_caps db, just to make sure we have something available to reference.

XXXXXXXXXXXXXXXXXXXXXXXXXXX

So far, no results - and my hunch is because the golden path of acquiring stat allocation and skills is through character creation. If we're changing it through commands, we have nothing to base off - so it gives us merely a blanket of what would be stats and 5 HP to keep us alive. Leveling up does not do anything, either.

We may need to look into more EQ_CORE_DLL injecting, and go down that rabbit hole.
I was also considering editting the Character Creation XML / UI to accomodate our new class.

XXXXXXXXXXXXXXXXXXXXXXXXXXXX

- Removed spawn of Telelocator in NRO + Pirate NPC (Just getting rid of remnants of local Velious stuff)
- Removed spawn of Telelocator in Butcherblock (No passage to Kunark)

XXXXXXXXXXXXXXXXXXXXXXXXXXXX

EXPERIMENTAL

//client.cpp

LINE 2185 under SetClassStartingSkills

Added:
if (cle->GetClientVersion() < static_cast<uint8>(EQ::versions::ClientVersion::Ro F2) && pp->class_ == Class::RuneKnight) {
pp->skills[EQ::skills::Skill1HBlunt] = 5;
pp->skills[EQ::skills::Skill1HSlashing] = 5;
pp->skills[EQ::skills::Skill2HBlunt] = 5;
pp->skills[EQ::skills::Skill2HSlashing] = 5;
pp->skills[EQ::skills::SkillAbjuration] = 5;
pp->skills[EQ::skills::SkillAlteration] = 5;
pp->skills[EQ::skills::SkillChanneling] = 5;
pp->skills[EQ::skills::SkillConjuration] = 5;
pp->skills[EQ::skills::SkillDefense] = 5;
pp->skills[EQ::skills::SkillDivination] = 5;
pp->skills[EQ::skills::SkillDoubleAttack] = 0;
pp->skills[EQ::skills::SkillDualWield] = 0;
pp->skills[EQ::skills::SkillEvocation] = 5;
pp->skills[EQ::skills::SkillHandtoHand] = 5;
pp->skills[EQ::skills::SkillMeditate] = 0;
pp->skills[EQ::skills::SkillOffense] = 5;
pp->skills[EQ::skills::SkillParry] = 5;
pp->skills[EQ::skills::Skill1HPiercing] = 5;
pp->skills[EQ::skills::SkillRiposte] = 0;
pp->skills[EQ::skills::SkillSafeFall] = 0;
pp->skills[EQ::skills::SkillSenseHeading] = 0;
pp->skills[EQ::skills::SkillSpecializeAbjure] = 0;
pp->skills[EQ::skills::SkillSpecializeAlteration] = 0;
pp->skills[EQ::skills::SkillSpecializeConjuration] = 0;
pp->skills[EQ::skills::SkillSpecializeDivination] = 0;
pp->skills[EQ::skills::SkillSpecializeEvocation] = 0;
pp->skills[EQ::skills::Skill2HPiercing] = 0;
}
// Trying to just cram the values into the game. They do it with the Berserker 2HPiercing, so maybe we can with our class.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Copied base_data from Shadowknights for Runeknights

INSERT INTO base_data
(level, class, hp, mana, end, hp_regen, end_regen, hp_fac, mana_fac, end_fac)
SELECT
level, '17', hp, mana, end, hp_regen, end_regen, hp_fac, mana_fac, end_fac
FROM
base_data
WHERE
class = 5;

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Reply With Quote
  #8  
Old 04-17-2025, 01:55 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG 4/17/2025

Poking at Character Creation right now.
Found these addresses change when selecting a class and match the class value (1 through 16) on the Character Creation screen. (Using CheatEngine)

The two addresses that I found seemed to be a "Selector" and "Final Value", however, they are inconsistent and random.
Digging further into it with Cheat Engine, point scanning the addresses, I can at least conclude two things.
There was a single result from the Selector pointmaps with the offset 0C, which is 011D43D4.
The offset for the Final Value is 00003374, however running scans on this didn't yield any results.
Not sure if coincidence, but the numbers 3374 also match up with 0x3374 DWORD for "Class" in EQData.h

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Experimental

Setting them to 17 has funny effects.
- Can't add or subtract any points.
- Right clicking any attribute buttons will subtract them to 0 and dump the points into "Points Left" - but I can't redistribute them.
Attempting to make a character shows "Missing Expansion" and "Select another Class"

Adding an entry to the Character Combination will validate the point allocation and allow us to redistribute them. (NICE)
Attempting to make a character shows "You cannot create this character because you have not unlocked this class."

So, now we have something in the backend blocking a class unlock. I'll need to dig further.

//eq_packet_structs.h
LINE 6079 - Membership_Entry_Struct membership_classes[16]; (( Setting this to 16 - arrays start at 0 position, so 16 = 17 ))

//rof2_structs.h
LINE 300 - Membership_Entry_Struct membership_classes[16]; (( Setting this to 16 - arrays start at 0 position, so 16 = 17 ))

//client.cpp
LINE 352 - class_entry_count = 16; (again, 16 = 17 because arrays)
LINE 357 - entry_id < 16 for classes (( Split the if statement checks here between race and class ))

Quote:
// RACIAL CHECKS
for (int entry_id=0; entry_id < 15; entry_id++)
{
if (entry_id == 0)
{
mds->membership_races[entry_id].purchase_id = 1;
mds->membership_races[entry_id].bitwise_entry = 0x1ffff;
}
else
{
mds->membership_races[entry_id].purchase_id = cur_purchase_id;

if (entry_id == 1)
{
mds->membership_races[entry_id].bitwise_entry = 4110;
}
else if (entry_id == 2)
{
mds->membership_races[entry_id].bitwise_entry = 4110;
}
else
{
if (entry_id == 12)
{
// Live Skips 4096
cur_bitwise_value *= 2;
}
mds->membership_races[entry_id].bitwise_entry = cur_bitwise_value;
}
cur_purchase_id++;
}
cur_bitwise_value *= 2;
}

// CLASS CHECKS
for (int entry_id = 0; entry_id < 16; entry_id++)
{
if (entry_id == 0)
{
mds->membership_classes[entry_id].purchase_id = 1;
mds->membership_classes[entry_id].bitwise_entry = 0x1ffff;
}
else
{
if (entry_id < 3)
{
mds->membership_classes[entry_id].purchase_id = cur_purchase_id;
}
else
{
mds->membership_classes[entry_id].purchase_id = cur_purchase_id2;
cur_purchase_id2++;
}

if (entry_id == 1)
{
mds->membership_classes[entry_id].bitwise_entry = 4614;
}
else if (entry_id == 2)
{
mds->membership_classes[entry_id].bitwise_entry = 4614;
}
else
{
if (entry_id == 12)
{
// Live Skips 4096
cur_bitwise_value *= 2;
}
mds->membership_classes[entry_id].bitwise_entry = cur_bitwise_value;
}
cur_purchase_id++;
}
cur_bitwise_value *= 2;
}
After recompiling, we are no longer crashing from the previous edits, but we're still met with the "Cannot create character because you have not unlocked this class." when setting the class to 17 with Cheat Engine.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Added Starting Items to Class 17
Reply With Quote
  #9  
Old 04-18-2025, 12:32 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG 4/18/2025

///////////////////////////////
Experimental

//client.cpp
LINE 302 - mc->classes = 4294967295 ( the maximum uint32 size ) - this is reading for the bitmask of available player classes. Setting it to the int32 maximum opens it up to accept class 17 at Character Creation (via Cheat Engine). Honestly, what would work is to rebuild the UI of Character Creation into drop down menus for Race/Class like it is for Deity and Starting Zones.

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

//rof_structs.h
LINE 300 - set membership classes to 16 like in previous mentioned structs

//mob.cpp
LINE 7698 - set uint16 class_bitmask to uint32

//embparser_api.cpp
LINE 5836 - set uint16 Perl__get_class_bitmask to uint32

//lua_client.cpp
LINE 3770 - set uint16 GetClassBitmask to uint32

//lua_general.cpp
LINE 5479 - set uint16 lua_get_class_bitmask to uint32

//lua_iteminst.cpp
LINE 58 - bool for IsEquipable changed from uint16 to uint32 for class_bitmask
LINE 494 - def for IsEquipable changed to expected uint32

//lua_iteminst.h
LINE 40 - bool IsEquipable changed from uint16 to uint32 for class_bitmask

//perl_questitem.cpp
LINE 190 - bool for Perl_QuestItem_IsEquipable changed from uint16 to uint32 for class_bitmask
LINE 420 - def for IsEquipable changed to expected uint32

//spells.cpp
LINE 7427 - GetItem check (was 65535, old MAX) set to 4294967295 -- (Prevent MQ2 exploitation method)

//base_spells_new_repository.h
LINE 142 - Added line int32_t "classes17" to accomodate added column in spells database.
LINE 389 - Added line for classes17 string
LINED 633 - Added line for classes17 string
LINE 909 - Added line "e.classes17" = 255;
Reply With Quote
  #10  
Old 04-18-2025, 02:25 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS 4/18/2025 continued...

//base_spells_new_repository.h
LINE 1184 - Added "e.classes17 = row[120] ? static_cast<int32_t>(atoi(row[120])) : 255;
-- Doing this, I needed to go through the rest of the array and re-align everything to +1 it's value following row 119
-- If I add another class in the future, I will need to readdress this again.

Quote:
e.id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.name = row[1] ? row[1] : "";
e.player_1 = row[2] ? row[2] : "BLUE_TRAIL";
e.teleport_zone = row[3] ? row[3] : "";
e.you_cast = row[4] ? row[4] : "";
e.other_casts = row[5] ? row[5] : "";
e.cast_on_you = row[6] ? row[6] : "";
e.cast_on_other = row[7] ? row[7] : "";
e.spell_fades = row[8] ? row[8] : "";
e.range_ = row[9] ? static_cast<int32_t>(atoi(row[9])) : 100;
e.aoerange = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.pushback = row[11] ? static_cast<int32_t>(atoi(row[11])) : 0;
e.pushup = row[12] ? static_cast<int32_t>(atoi(row[12])) : 0;
e.cast_time = row[13] ? static_cast<int32_t>(atoi(row[13])) : 0;
e.recovery_time = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.recast_time = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.buffdurationformula = row[16] ? static_cast<int32_t>(atoi(row[16])) : 7;
e.buffduration = row[17] ? static_cast<int32_t>(atoi(row[17])) : 65;
e.AEDuration = row[18] ? static_cast<int32_t>(atoi(row[18])) : 0;
e.mana = row[19] ? static_cast<int32_t>(atoi(row[19])) : 0;
e.effect_base_value1 = row[20] ? static_cast<int32_t>(atoi(row[20])) : 100;
e.effect_base_value2 = row[21] ? static_cast<int32_t>(atoi(row[21])) : 0;
e.effect_base_value3 = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
e.effect_base_value4 = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
e.effect_base_value5 = row[24] ? static_cast<int32_t>(atoi(row[24])) : 0;
e.effect_base_value6 = row[25] ? static_cast<int32_t>(atoi(row[25])) : 0;
e.effect_base_value7 = row[26] ? static_cast<int32_t>(atoi(row[26])) : 0;
e.effect_base_value8 = row[27] ? static_cast<int32_t>(atoi(row[27])) : 0;
e.effect_base_value9 = row[28] ? static_cast<int32_t>(atoi(row[28])) : 0;
e.effect_base_value10 = row[29] ? static_cast<int32_t>(atoi(row[29])) : 0;
e.effect_base_value11 = row[30] ? static_cast<int32_t>(atoi(row[30])) : 0;
e.effect_base_value12 = row[31] ? static_cast<int32_t>(atoi(row[31])) : 0;
e.effect_limit_value1 = row[32] ? static_cast<int32_t>(atoi(row[32])) : 0;
e.effect_limit_value2 = row[33] ? static_cast<int32_t>(atoi(row[33])) : 0;
e.effect_limit_value3 = row[34] ? static_cast<int32_t>(atoi(row[34])) : 0;
e.effect_limit_value4 = row[35] ? static_cast<int32_t>(atoi(row[35])) : 0;
e.effect_limit_value5 = row[36] ? static_cast<int32_t>(atoi(row[36])) : 0;
e.effect_limit_value6 = row[37] ? static_cast<int32_t>(atoi(row[37])) : 0;
e.effect_limit_value7 = row[38] ? static_cast<int32_t>(atoi(row[38])) : 0;
e.effect_limit_value8 = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
e.effect_limit_value9 = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.effect_limit_value10 = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.effect_limit_value11 = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
e.effect_limit_value12 = row[43] ? static_cast<int32_t>(atoi(row[43])) : 0;
e.max1 = row[44] ? static_cast<int32_t>(atoi(row[44])) : 0;
e.max2 = row[45] ? static_cast<int32_t>(atoi(row[45])) : 0;
e.max3 = row[46] ? static_cast<int32_t>(atoi(row[46])) : 0;
e.max4 = row[47] ? static_cast<int32_t>(atoi(row[47])) : 0;
e.max5 = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0;
e.max6 = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0;
e.max7 = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0;
e.max8 = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0;
e.max9 = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0;
e.max10 = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0;
e.max11 = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0;
e.max12 = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0;
e.icon = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0;
e.memicon = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0;
e.components1 = row[58] ? static_cast<int32_t>(atoi(row[58])) : -1;
e.components2 = row[59] ? static_cast<int32_t>(atoi(row[59])) : -1;
e.components3 = row[60] ? static_cast<int32_t>(atoi(row[60])) : -1;
e.components4 = row[61] ? static_cast<int32_t>(atoi(row[61])) : -1;
e.component_counts1 = row[62] ? static_cast<int32_t>(atoi(row[62])) : 1;
e.component_counts2 = row[63] ? static_cast<int32_t>(atoi(row[63])) : 1;
e.component_counts3 = row[64] ? static_cast<int32_t>(atoi(row[64])) : 1;
e.component_counts4 = row[65] ? static_cast<int32_t>(atoi(row[65])) : 1;
e.NoexpendReagent1 = row[66] ? static_cast<int32_t>(atoi(row[66])) : -1;
e.NoexpendReagent2 = row[67] ? static_cast<int32_t>(atoi(row[67])) : -1;
e.NoexpendReagent3 = row[68] ? static_cast<int32_t>(atoi(row[68])) : -1;
e.NoexpendReagent4 = row[69] ? static_cast<int32_t>(atoi(row[69])) : -1;
e.formula1 = row[70] ? static_cast<int32_t>(atoi(row[70])) : 100;
e.formula2 = row[71] ? static_cast<int32_t>(atoi(row[71])) : 100;
e.formula3 = row[72] ? static_cast<int32_t>(atoi(row[72])) : 100;
e.formula4 = row[73] ? static_cast<int32_t>(atoi(row[73])) : 100;
e.formula5 = row[74] ? static_cast<int32_t>(atoi(row[74])) : 100;
e.formula6 = row[75] ? static_cast<int32_t>(atoi(row[75])) : 100;
e.formula7 = row[76] ? static_cast<int32_t>(atoi(row[76])) : 100;
e.formula8 = row[77] ? static_cast<int32_t>(atoi(row[77])) : 100;
e.formula9 = row[78] ? static_cast<int32_t>(atoi(row[78])) : 100;
e.formula10 = row[79] ? static_cast<int32_t>(atoi(row[79])) : 100;
e.formula11 = row[80] ? static_cast<int32_t>(atoi(row[80])) : 100;
e.formula12 = row[81] ? static_cast<int32_t>(atoi(row[81])) : 100;
e.LightType = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.goodEffect = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
e.Activated = row[84] ? static_cast<int32_t>(atoi(row[84])) : 0;
e.resisttype = row[85] ? static_cast<int32_t>(atoi(row[85])) : 0;
e.effectid1 = row[86] ? static_cast<int32_t>(atoi(row[86])) : 254;
e.effectid2 = row[87] ? static_cast<int32_t>(atoi(row[87])) : 254;
e.effectid3 = row[88] ? static_cast<int32_t>(atoi(row[88])) : 254;
e.effectid4 = row[89] ? static_cast<int32_t>(atoi(row[89])) : 254;
e.effectid5 = row[90] ? static_cast<int32_t>(atoi(row[90])) : 254;
e.effectid6 = row[91] ? static_cast<int32_t>(atoi(row[91])) : 254;
e.effectid7 = row[92] ? static_cast<int32_t>(atoi(row[92])) : 254;
e.effectid8 = row[93] ? static_cast<int32_t>(atoi(row[93])) : 254;
e.effectid9 = row[94] ? static_cast<int32_t>(atoi(row[94])) : 254;
e.effectid10 = row[95] ? static_cast<int32_t>(atoi(row[95])) : 254;
e.effectid11 = row[96] ? static_cast<int32_t>(atoi(row[96])) : 254;
e.effectid12 = row[97] ? static_cast<int32_t>(atoi(row[97])) : 254;
e.targettype = row[98] ? static_cast<int32_t>(atoi(row[98])) : 2;
e.basediff = row[99] ? static_cast<int32_t>(atoi(row[99])) : 0;
e.skill = row[100] ? static_cast<int32_t>(atoi(row[100])) : 98;
e.zonetype = row[101] ? static_cast<int32_t>(atoi(row[101])) : -1;
e.EnvironmentType = row[102] ? static_cast<int32_t>(atoi(row[102])) : 0;
e.TimeOfDay = row[103] ? static_cast<int32_t>(atoi(row[103])) : 0;
e.classes1 = row[104] ? static_cast<int32_t>(atoi(row[104])) : 255;
e.classes2 = row[105] ? static_cast<int32_t>(atoi(row[105])) : 255;
e.classes3 = row[106] ? static_cast<int32_t>(atoi(row[106])) : 255;
e.classes4 = row[107] ? static_cast<int32_t>(atoi(row[107])) : 255;
e.classes5 = row[108] ? static_cast<int32_t>(atoi(row[108])) : 255;
e.classes6 = row[109] ? static_cast<int32_t>(atoi(row[109])) : 255;
e.classes7 = row[110] ? static_cast<int32_t>(atoi(row[110])) : 255;
e.classes8 = row[111] ? static_cast<int32_t>(atoi(row[111])) : 255;
e.classes9 = row[112] ? static_cast<int32_t>(atoi(row[112])) : 255;
e.classes10 = row[113] ? static_cast<int32_t>(atoi(row[113])) : 255;
e.classes11 = row[114] ? static_cast<int32_t>(atoi(row[114])) : 255;
e.classes12 = row[115] ? static_cast<int32_t>(atoi(row[115])) : 255;
e.classes13 = row[116] ? static_cast<int32_t>(atoi(row[116])) : 255;
e.classes14 = row[117] ? static_cast<int32_t>(atoi(row[117])) : 255;
e.classes15 = row[118] ? static_cast<int32_t>(atoi(row[118])) : 255;
e.classes16 = row[119] ? static_cast<int32_t>(atoi(row[119])) : 255;
e.classes17 = row[120] ? static_cast<int32_t>(atoi(row[119])) : 255;
e.CastingAnim = row[121] ? static_cast<int32_t>(atoi(row[121])) : 44;
e.TargetAnim = row[122] ? static_cast<int32_t>(atoi(row[122])) : 13;
e.TravelType = row[123] ? static_cast<int32_t>(atoi(row[123])) : 0;
e.SpellAffectIndex = row[124] ? static_cast<int32_t>(atoi(row[124])) : -1;
e.disallow_sit = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.deities0 = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.deities1 = row[127] ? static_cast<int32_t>(atoi(row[127])) : 0;
e.deities2 = row[128] ? static_cast<int32_t>(atoi(row[128])) : 0;
e.deities3 = row[129] ? static_cast<int32_t>(atoi(row[129])) : 0;
e.deities4 = row[130] ? static_cast<int32_t>(atoi(row[130])) : 0;
e.deities5 = row[131] ? static_cast<int32_t>(atoi(row[131])) : 0;
e.deities6 = row[132] ? static_cast<int32_t>(atoi(row[132])) : 0;
e.deities7 = row[133] ? static_cast<int32_t>(atoi(row[133])) : 0;
e.deities8 = row[134] ? static_cast<int32_t>(atoi(row[134])) : 0;
e.deities9 = row[135] ? static_cast<int32_t>(atoi(row[135])) : 0;
e.deities10 = row[136] ? static_cast<int32_t>(atoi(row[136])) : 0;
e.deities11 = row[137] ? static_cast<int32_t>(atoi(row[137])) : 0;
e.deities12 = row[138] ? static_cast<int32_t>(atoi(row[138])) : 0;
e.deities13 = row[139] ? static_cast<int32_t>(atoi(row[139])) : 0;
e.deities14 = row[140] ? static_cast<int32_t>(atoi(row[140])) : 0;
e.deities15 = row[141] ? static_cast<int32_t>(atoi(row[141])) : 0;
e.deities16 = row[142] ? static_cast<int32_t>(atoi(row[142])) : 0;
e.field142 = row[143] ? static_cast<int32_t>(atoi(row[143])) : 100;
e.field143 = row[144] ? static_cast<int32_t>(atoi(row[144])) : 0;
e.new_icon = row[145] ? static_cast<int32_t>(atoi(row[145])) : 161;
e.spellanim = row[146] ? static_cast<int32_t>(atoi(row[146])) : 0;
e.uninterruptable = row[147] ? static_cast<int32_t>(atoi(row[147])) : 0;
e.ResistDiff = row[148] ? static_cast<int32_t>(atoi(row[148])) : -150;
e.dot_stacking_exempt = row[149] ? static_cast<int32_t>(atoi(row[149])) : 0;
e.deleteable = row[150] ? static_cast<int32_t>(atoi(row[150])) : 0;
e.RecourseLink = row[151] ? static_cast<int32_t>(atoi(row[151])) : 0;
e.no_partial_resist = row[152] ? static_cast<int32_t>(atoi(row[152])) : 0;
e.field152 = row[153] ? static_cast<int32_t>(atoi(row[153])) : 0;
e.field153 = row[154] ? static_cast<int32_t>(atoi(row[154])) : 0;
e.short_buff_box = row[155] ? static_cast<int32_t>(atoi(row[155])) : -1;
e.descnum = row[156] ? static_cast<int32_t>(atoi(row[156])) : 0;
e.typedescnum = row[157] ? static_cast<int32_t>(atoi(row[157])) : 0;
e.effectdescnum = row[158] ? static_cast<int32_t>(atoi(row[158])) : 0;
e.effectdescnum2 = row[159] ? static_cast<int32_t>(atoi(row[159])) : 0;
e.npc_no_los = row[160] ? static_cast<int32_t>(atoi(row[160])) : 0;
e.field160 = row[161] ? static_cast<int32_t>(atoi(row[161])) : 0;
e.reflectable = row[162] ? static_cast<int32_t>(atoi(row[162])) : 0;
e.bonushate = row[163] ? static_cast<int32_t>(atoi(row[163])) : 0;
e.field163 = row[164] ? static_cast<int32_t>(atoi(row[164])) : 100;
e.field164 = row[165] ? static_cast<int32_t>(atoi(row[165])) : -150;
e.ldon_trap = row[166] ? static_cast<int32_t>(atoi(row[166])) : 0;
e.EndurCost = row[167] ? static_cast<int32_t>(atoi(row[167])) : 0;
e.EndurTimerIndex = row[168] ? static_cast<int32_t>(atoi(row[168])) : 0;
e.IsDiscipline = row[169] ? static_cast<int32_t>(atoi(row[169])) : 0;
e.field169 = row[170] ? static_cast<int32_t>(atoi(row[170])) : 0;
e.field170 = row[171] ? static_cast<int32_t>(atoi(row[171])) : 0;
e.field171 = row[172] ? static_cast<int32_t>(atoi(row[172])) : 0;
e.field172 = row[173] ? static_cast<int32_t>(atoi(row[173])) : 0;
e.HateAdded = row[174] ? static_cast<int32_t>(atoi(row[174])) : 0;
e.EndurUpkeep = row[175] ? static_cast<int32_t>(atoi(row[175])) : 0;
e.numhitstype = row[176] ? static_cast<int32_t>(atoi(row[176])) : 0;
e.numhits = row[177] ? static_cast<int32_t>(atoi(row[177])) : 0;
e.pvpresistbase = row[178] ? static_cast<int32_t>(atoi(row[178])) : -150;
e.pvpresistcalc = row[179] ? static_cast<int32_t>(atoi(row[179])) : 100;
e.pvpresistcap = row[180] ? static_cast<int32_t>(atoi(row[180])) : -150;
e.spell_category = row[181] ? static_cast<int32_t>(atoi(row[181])) : -99;
e.pvp_duration = row[182] ? static_cast<int32_t>(atoi(row[182])) : 0;
e.pvp_duration_cap = row[183] ? static_cast<int32_t>(atoi(row[183])) : 0;
e.pcnpc_only_flag = row[184] ? static_cast<int32_t>(atoi(row[184])) : 0;
e.cast_not_standing = row[185] ? static_cast<int32_t>(atoi(row[185])) : 0;
e.can_mgb = row[186] ? static_cast<int32_t>(atoi(row[186])) : 0;
e.nodispell = row[187] ? static_cast<int32_t>(atoi(row[187])) : -1;
e.npc_category = row[188] ? static_cast<int32_t>(atoi(row[188])) : 0;
e.npc_usefulness = row[189] ? static_cast<int32_t>(atoi(row[189])) : 0;
e.MinResist = row[190] ? static_cast<int32_t>(atoi(row[190])) : 0;
e.MaxResist = row[191] ? static_cast<int32_t>(atoi(row[191])) : 0;
e.viral_targets = row[192] ? static_cast<int32_t>(atoi(row[192])) : 0;
e.viral_timer = row[193] ? static_cast<int32_t>(atoi(row[193])) : 0;
e.nimbuseffect = row[194] ? static_cast<int32_t>(atoi(row[194])) : 0;
e.ConeStartAngle = row[195] ? static_cast<int32_t>(atoi(row[195])) : 0;
e.ConeStopAngle = row[196] ? static_cast<int32_t>(atoi(row[196])) : 0;
e.sneaking = row[197] ? static_cast<int32_t>(atoi(row[197])) : 0;
e.not_extendable = row[198] ? static_cast<int32_t>(atoi(row[198])) : 0;
e.field198 = row[199] ? static_cast<int32_t>(atoi(row[199])) : 0;
e.field199 = row[200] ? static_cast<int32_t>(atoi(row[200])) : 1;
e.suspendable = row[201] ? static_cast<int32_t>(atoi(row[201])) : 0;
e.viral_range = row[202] ? static_cast<int32_t>(atoi(row[202])) : 0;
e.songcap = row[203] ? static_cast<int32_t>(atoi(row[203])) : 0;
e.field203 = row[204] ? static_cast<int32_t>(atoi(row[204])) : 0;
e.field204 = row[205] ? static_cast<int32_t>(atoi(row[205])) : 0;
e.no_block = row[206] ? static_cast<int32_t>(atoi(row[206])) : 0;
e.field206 = row[207] ? static_cast<int32_t>(atoi(row[207])) : -1;
e.spellgroup = row[208] ? static_cast<int32_t>(atoi(row[208])) : 0;
e.rank_ = row[209] ? static_cast<int32_t>(atoi(row[209])) : 0;
e.field209 = row[210] ? static_cast<int32_t>(atoi(row[210])) : 0;
e.field210 = row[211] ? static_cast<int32_t>(atoi(row[211])) : 1;
e.CastRestriction = row[212] ? static_cast<int32_t>(atoi(row[212])) : 0;
e.allowrest = row[213] ? static_cast<int32_t>(atoi(row[213])) : 0;
e.InCombat = row[214] ? static_cast<int32_t>(atoi(row[214])) : 0;
e.OutofCombat = row[215] ? static_cast<int32_t>(atoi(row[215])) : 0;
e.field215 = row[216] ? static_cast<int32_t>(atoi(row[216])) : 0;
e.field216 = row[217] ? static_cast<int32_t>(atoi(row[217])) : 0;
e.field217 = row[218] ? static_cast<int32_t>(atoi(row[218])) : 0;
e.aemaxtargets = row[219] ? static_cast<int32_t>(atoi(row[219])) : 0;
e.maxtargets = row[220] ? static_cast<int32_t>(atoi(row[220])) : 0;
e.field220 = row[221] ? static_cast<int32_t>(atoi(row[221])) : 0;
e.field221 = row[222] ? static_cast<int32_t>(atoi(row[222])) : 0;
e.field222 = row[223] ? static_cast<int32_t>(atoi(row[223])) : 0;
e.field223 = row[224] ? static_cast<int32_t>(atoi(row[224])) : 0;
e.persistdeath = row[225] ? static_cast<int32_t>(atoi(row[225])) : 0;
e.field225 = row[226] ? static_cast<int32_t>(atoi(row[226])) : 0;
e.field226 = row[227] ? static_cast<int32_t>(atoi(row[227])) : 0;
e.min_dist = row[228] ? strtof(row[227], nullptr) : 0;
e.min_dist_mod = row[229] ? strtof(row[228], nullptr) : 0;
e.max_dist = row[230] ? strtof(row[229], nullptr) : 0;
e.max_dist_mod = row[231] ? strtof(row[230], nullptr) : 0;
e.min_range = row[232] ? static_cast<int32_t>(atoi(row[232])) : 0;
e.field232 = row[233] ? static_cast<int32_t>(atoi(row[233])) : 0;
e.field233 = row[234] ? static_cast<int32_t>(atoi(row[234])) : 0;
e.field234 = row[235] ? static_cast<int32_t>(atoi(row[235])) : 0;
e.field235 = row[236] ? static_cast<int32_t>(atoi(row[236])) : 0;
e.field236 = row[237] ? static_cast<int32_t>(atoi(row[237])) : 0;
Reply With Quote
  #11  
Old 04-18-2025, 02:30 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS 4/18/2025 continued....part 2
//base_spells_new_repository.h

LINE 1454 - Added in line for v.pushback for classes17
-- Again, need to push each number in the array forward by +1 -- and will need to revisit this if I make another class
(Won't post it here because forums throw errors, but its a long list.)

LINE 1713 - ADDED in a line for classes17 (thankfully no array to adjust here..)
LINE 1981 - ADDED in a line for classes17 (thankfully no array to adjust here..)

LINE 2251 - Another array like mentioned above. Added a line here for classes17
Bump it +1 where necessary.

LINE 2507 - Another array like mentioned above. Added a line here for classes17
Bump it +1 where necessary.

LINE 2823 - ADDED in a line for classes17 (thankfully no array to adjust here..)
LINE 3077 - ADDED in a line for classes17 (thankfully no array to adjust here..)

//item_data.cpp
LINE 170 - IsEquipable Class set to uint32
LINE 176 - IsClassEquipable Class set to uint32

//item_data.h
LINE 544 - IsEquipable Class set to uint32
LINE 545 - IsClassEquipable Class set to uint32

//item_instance.cpp
LINE 234 - IsEquipable Class set to uint32
LINE 244 - IsEquipable Class set to uint32

//item_instance.h
LINE 101 - IsEquipable class_ set to uint32
LINE 103 - IsClassEquipable class_ set to uint32

//mob.cpp
LINE 7688 uint16 item_class set to uint32

Quote:
//client.cpp

LINE 2185 under SetClassStartingSkills

Added:
if (cle->GetClientVersion() < static_cast<uint8>(EQ::versions::ClientVersion::Ro F2) && pp->class_ == Class::RuneKnight) {
pp->skills[EQ::skills::Skill1HBlunt] = 5;
pp->skills[EQ::skills::Skill1HSlashing] = 5;
pp->skills[EQ::skills::Skill2HBlunt] = 5;
pp->skills[EQ::skills::Skill2HSlashing] = 5;
pp->skills[EQ::skills::SkillAbjuration] = 5;
pp->skills[EQ::skills::SkillAlteration] = 5;
pp->skills[EQ::skills::SkillChanneling] = 5;
pp->skills[EQ::skills::SkillConjuration] = 5;
pp->skills[EQ::skills::SkillDefense] = 5;
pp->skills[EQ::skills::SkillDivination] = 5;
pp->skills[EQ::skills::SkillDoubleAttack] = 0;
pp->skills[EQ::skills::SkillDualWield] = 0;
pp->skills[EQ::skills::SkillEvocation] = 5;
pp->skills[EQ::skills::SkillHandtoHand] = 5;
pp->skills[EQ::skills::SkillMeditate] = 0;
pp->skills[EQ::skills::SkillOffense] = 5;
pp->skills[EQ::skills::SkillParry] = 5;
pp->skills[EQ::skills::Skill1HPiercing] = 5;
pp->skills[EQ::skills::SkillRiposte] = 0;
pp->skills[EQ::skills::SkillSafeFall] = 0;
pp->skills[EQ::skills::SkillSenseHeading] = 0;
pp->skills[EQ::skills::SkillSpecializeAbjure] = 0;
pp->skills[EQ::skills::SkillSpecializeAlteration] = 0;
pp->skills[EQ::skills::SkillSpecializeConjuration] = 0;
pp->skills[EQ::skills::SkillSpecializeDivination] = 0;
pp->skills[EQ::skills::SkillSpecializeEvocation] = 0;
pp->skills[EQ::skills::Skill2HPiercing] = 0;
}
// Trying to just cram the values into the game. They do it with the Berserker 2HPiercing, so maybe we can with our class.
Gutted that out - not necessary.

-- Copied the skilltree of Shadowknights for RuneKnight
-- Removed Archery & Throwing from RuneKnight (They have spells, they don't need it.)

Made sure to download the BaseData and Skill_Caps to client folder. Stats and Skills now show in game for RuneKnight, but we still can't open the GM window for our class.
This has to be player or client based, because we can kick open the Training Window on a different class using the Rune Knight GM.

//attack.cpp
LINE 716 - Added RuneKnight to switch case to receive warrior softcaps
LINE 3939 - Added RuneKnight to Classic CheckTripleAttack and Switch Case to receive ClassicTripleAttackChanceWarrior

//client_mods.cpp
LINE 456 - Added in switch case for RuneKnight level multipliers (copied Shadowknight)

//client_process.cpp
Commented out method at 1626 that doubles down for "use your own trainer" - Just a precaution for now...

//base_merchantlist_repository
LINE 137 - Set default classes_required to 131071 (theres like 3 of these, so we'll set them all to 131071) -- this fixes the issue of class 17 not being able to buy from any merchant.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Modified PEQ database so that items can now be marked for 65536 (RuneKnight) - make it a lot easier than typing data and doing math in SQL.
Reply With Quote
  #12  
Old 04-19-2025, 10:13 AM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG 4/19/2025

So far, as of today, I'm at this current state in developing the new class. A lot of it is becoming client dependent, particularly UI and strings. I know that with EQ_CORE_DLL, strings and values can be injected, but that will be a rabbit hole on it's own.

Quote:
NEW CLASS ISSUES
1. Inventory long name displays as "Unknown" and Item Descriptions do not display shortname if they can equip

2. Class36 (Trainers) do not kick open training windows.
AllTrainers set to true, all trainers ignore Class17.
Class36 will train any other class though.

3. We cannot naturally create a class17 via Character Creation, can only be tested with Cheat Engine.

4. Class17 doesn't show mana bar on UI.

5. Sometimes while attacking, Class17 show as "Pain and suffering"
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

//items
- Fixed a bunch of plate items that couldn't be equipped by certain classes (145 vs 151)
- Added RuneKnight to several thousand items via SQL bitmask updates.
(There will still probably be a few one-offs here and there, more than likely.)

//Flash of Runes Spell-line

- Minor Runic Shield added to game.
Currently in testing - Applies a damage absorption to the player, damage mitigation percentage, spell mitigation chance, and some AC. Also adds Hate.
The concept of the spell is for Rune Knights to lean into it for tanking purposes.

////base_spells_new_repository.h
Moved all references to classes17 to the end of each array - and undid my aforementioned +1 shifts.
This could be causing desyncing issues in the client interpretation of new_spells and the spells_us.txt - plus also easier to only need one hook for each array in the future instead of needing to accomodate 100+

//GAMEPLAY UPDATES

WARRIOR
-- To balance Warriors out from being permanently replaced by Rune Knight, Warriors have received a base increase to their HP from 25 to 35. They will have a significant HP pool advantage over any class. This bonus goes parabolic starting at level 80, where it jumps to +100 base per level all the way up to Level 100. Warriors should have better advantages to solo with this added bonus and not be as gear dependent.


//shareddb.cpp

LINE 1775 - editted check to accomodate the math to find classes - we have to put an if statement in here so it goes to row 237 for class 17
Quote:
for(y=0; y < Class::PLAYER_CLASS_COUNT;y++)
if (y == 17)
{
sp[tempid].classes[y] = Strings::ToInt(row[237]);
}
else if (y < 17)
{
sp[tempid].classes[y] = Strings::ToInt(row[104 + y]);
}
//effects.cpp
LINE 141, 193, 297, 343, 485, 539, 572 - set modulo from 17 to 18 before it subtracts 1 from the highest class number

//mob.cpp
LINE 7257 - set modulo from 17 to 18 before it subtracts 1 from highest class number

//spell_effects.cpp
LINE 4821, 4839, 5547, 5569 - set modulo from 17 to 18 before it subtracts 1 from highest class number
LINE 7130 - Included RuneKnight in "other" check for SKs

//spells.cpp
LINE 4378 - Included RuneKnight in SINGLE REFLECT check (16 to 17)
LINE 4387 - Included RuneKnight in REFLECT ALL check (16 to 17)
Reply With Quote
  #13  
Old 04-20-2025, 02:48 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG 4/20/2025

Issue hit after resetting the arrays yesterday - we're unable to memorize spells as RuneKnight. It's reading it's level as CastingAnim, not classes17.
This could be because we're not checking for Row 237, which is where classes17 is now.

//spdat.h
LINE 1651 calculates PLAYER_CLASS_COUNT -- we want to reroute how we get the spell levels so it doesn't look at CastingAnim when the class_id hits 17.
Added in an entry at the end of this list to just cover the RUNE KNIGHT specifically. (classes17)

//spdat.cpp
LINE 977 - GetSpellMinimumLevel
Quote:
for (int i = 0; i < Class::PLAYER_CLASS_COUNT; i++) {
if (spell.classes[i] < minimum_level) {
if (i == 17)
{
minimum_level = spell.classes17;
}
else
{
minimum_level = spell.classes[i];
}

}
}
If iterator hits 17, go off classes17.
Else, look at classes1 through classes16

LINE 1007 - GetSpellLevel
Quote:
if (class_id == 17)
{
return spells[spell_id].classes17;
}

else
{
return spells[spell_id].classes[class_id];
}
These two hand in hand should at least point to the classes17 now if the logic hits 17.
We are still hitting CastingAnim for classes17's "required level" for spells - so we inevitably will need to write a hook in for it, probably through EQ_CORE_DLL
Reply With Quote
  #14  
Old Yesterday, 06:01 PM
m0th
Fire Beetle
 
Join Date: Apr 2025
Posts: 18
Default

PROGRESS LOG 4/26/2025

Been a few days since my last post. I got a bit jumbled about working on generators and trying to get spells working for class17.

Put in a bunch of XML edits to get a button for class17 to appear on the character creation. Add that to server files.

I put things to the side for now and started working on a MQ2 plugin I am calling "CharacterCreationOverride" or "MQ2CC" for short. Right now I have only gotten it working partially in pulling data from the Character Creation.

The goal is inevitably to use the plugin to allow golden path character creation for class17 and eventually port it to eq core dll for ease of access.

More coming in the future... for now, back to coding.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 04:25 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3