• You've discovered RedGuides, an EverQuest multi-boxing and scripting community 🧙‍♀️⚙️. We want you to play several EQ characters at once, come join us and say hello! 👋

Other - Server Code and Tips For Those Running Own Server

fleqfan

oblivious
So as I have been running my own server, I have found some weird quirks and issues and what-not that I have been tackling on a case by case basis. Since my server is MQ friendly I thought I would share some off the issues and solutions I have found here.

First one is to turn off flagging a character for MQ Targeting, that is targeting something that they should not be able to.

MQ Targeting - Run this as an SQL Query in your database

Turn Off MQ Targeting
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:AllowMQTarget', `rule_value`='true', `notes`='Disables putting players in the \'hackers\' list for targeting beyond the clip plane or attempting to target something untargetable' WHERE `ruleset_id`=1 AND `rule_name`='Character:AllowMQTarget';

No Drop Turned Off
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Items:DisableNoDrop', `rule_value`='true', `notes`='Enable this to disable No Drop Items' WHERE `ruleset_id`=1 AND `rule_name`='Items:DisableNoDrop';

Bag and Type 1 Aug Distiller to Tutorial Vendor
Code:
INSERT INTO `merchantlist` (`merchantid`, `slot`, `item`, `faction_required`, `level_required`, `min_status`, `max_status`, `alt_currency_cost`, `classes_required`, `probability`, `bucket_name`, `bucket_value`, `bucket_comparison`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (189021, 20, 17005, -1100, 0, 0, 255, 0, 65535, 100, '', '', 0, -1, -1, NULL, NULL);
INSERT INTO `merchantlist` (`merchantid`, `slot`, `item`, `faction_required`, `level_required`, `min_status`, `max_status`, `alt_currency_cost`, `classes_required`, `probability`, `bucket_name`, `bucket_value`, `bucket_comparison`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (189021, 20, 47001, -1100, 0, 0, 255, 0, 65535, 100, '', '', 0, -1, -1, NULL, NULL);

HP End and Mana Regen Doubled From Default
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:HPRegenMultiplier', `rule_value`='200', `notes`='The hitpoint regeneration is multiplied by value/100 (up to the caps)' WHERE `ruleset_id`=1 AND `rule_name`='Character:HPRegenMultiplier';
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:EnduranceRegenMultiplier', `rule_value`='200', `notes`='The endurance regeneration is multiplied by value/100 (up to the caps)' WHERE `ruleset_id`=1 AND `rule_name`='Character:EnduranceRegenMultiplier';
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:ManaRegenMultiplier', `rule_value`='200', `notes`='The mana regeneration is multiplied by value/100 (up to the caps)' WHERE `ruleset_id`=1 AND `rule_name`='Character:ManaRegenMultiplier';

Out of Combat Timer reduced for rulesets 1 5 6
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:RestRegenTimeToActivate', `rule_value`='15', `notes`='Time in seconds for rest state regen to kick in' WHERE `ruleset_id`=1 AND `rule_name`='Character:RestRegenTimeToActivate';
UPDATE `rule_values` SET `ruleset_id`=5, `rule_name`='Character:RestRegenTimeToActivate', `rule_value`='15', `notes`='Time in seconds for rest state regen to kick in' WHERE `ruleset_id`=5 AND `rule_name`='Character:RestRegenTimeToActivate';
UPDATE `rule_values` SET `ruleset_id`=6, `rule_name`='Character:RestRegenTimeToActivate', `rule_value`='15', `notes`='Time in seconds for rest state regen to kick in' WHERE `ruleset_id`=6 AND `rule_name`='Character:RestRegenTimeToActivate';

No Losing of Levels
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:DeathKeepLevel', `rule_value`='true', `notes`='Players can not drop below 0% experience from death.' WHERE `ruleset_id`=1 AND `rule_name`='Character:DeathKeepLevel';

Corpses and Death
Code:
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:LeaveNakedCorpses', `rule_value`='true', `notes`='Setting whether you leave a corpse without items' WHERE `ruleset_id`=1 AND `rule_name`='Character:LeaveNakedCorpses';
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:DeathItemLossLevel', `rule_value`='71', `notes`='From this level on, items are left in the corpse when LeaveCorpses is activated' WHERE `ruleset_id`=1 AND `rule_name`='Character:DeathItemLossLevel';
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:LeaveCorpses', `rule_value`='true', `notes`='Setting whether you leave a corpse behind' WHERE `ruleset_id`=1 AND `rule_name`='Character:LeaveCorpses';
UPDATE `rule_values` SET `ruleset_id`=1, `rule_name`='Character:UnmemSpellsOnDeath', `rule_value`='false', `notes`='Setting whether at death all memorized Spells are forgotten' WHERE `ruleset_id`=1 AND `rule_name`='Character:UnmemSpellsOnDeath';

Since max level is 70 on my server, I make sure that when one dies items are not left on the corpse (corpse run) and that a naked corpse is left so it can get a rez. I also removed where it would unmem spells on death.

My version of Guild Lobby would not let me zone anywhere without GM commands to I found this searching to fix.

Fix GL Doors
Code:
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `close_timer_ms`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (2040, 37, 'PoKnowledge', 0, 'POKRVPORT500', 908.668, 1228.06, -156.248, 384, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'mistythicket', 0, 662, -7, 4, 2, 0, 0, 100, -559.555, 4294967232, 0, 5000, 0, -1, -1, NULL, NULL);
UPDATE `doors` SET `version` = 0 WHERE `id` = 36632;
UPDATE `doors` SET `door_param` = 0, `dest_instance` = 0, `client_version_mask` = 4294967295 WHERE `id` = 36666;
UPDATE `doors` SET `dest_instance` = 0, `client_version_mask` = 4294967295 WHERE `id` = 36667;
COMMIT;

Update "Your Server"\quests\guildlobby\player.pl

\quests\guildlobby\player.pl
Code:
sub EVENT_CLICKDOOR
{
    if($doorid == 2 || $doorid == 4 || $doorid == 40 || $doorid == 42)
    {
            if($uguild_id > 0)
            {
                  if (defined($qglobals{"ginstance$uguild_id"}))
                  {
                    $guildinstance = $qglobals{"ginstance$uguild_id"};
                    quest::AssignToInstance($guildinstance);
                    quest::MovePCInstance(345, $guildinstance, -1.00, -1.00, 3.34);
                  }
                  else
                  {
                    $guildinstance = quest::CreateInstance("guildhall", 1, 86400);
                    quest::AssignToInstance($guildinstance);
                    quest::setglobal("ginstance$uguild_id",$guildinstance,7,"H24");
                    quest::MovePCInstance(345, $guildinstance, -1.00, -1.00, 3.34)
                  }
            }
      }
      if((($doorid >= 5) && ($doorid <= 38)) ||  (($doorid >= 43) && ($doorid <= 76)))
      {
        $client->OpenLFGuildWindow();
      }
}
    
sub EVENT_TIMER
{
    if($timer == 1)
    {
        quest::MovePCInstance(344,5,$x,$y,$z,225);
    }
    if($timer == 2)
    {
        quest::movepc(344,$x,$y,$z,225);
    }
}


Also need to update "Your Server"\quests\guildhall\player.pl

\quests\guildhall\player.pl
Code:
# Guild Hall Regen Pool Script - Player Portion

sub EVENT_SIGNAL {
  if ($signal == 1) {
    quest::settimer("DoRegen", 6);
  }
  if ($signal == 2) {
    quest::stoptimer("DoRegen");
  }
}

sub EVENT_ENTERZONE {
  quest::settimer("ZoneIn", 3);
}

sub EVENT_ZONE {
  quest::stoptimer("DoRegen"); #Stop the timer if they zone
}

sub EVENT_TIMER {
  if ($timer eq "ZoneIn") {
    quest::stoptimer("ZoneIn");
    quest::signalwith(345004,$charid);
  } else {
    quest::stoptimer("DoRegen");
    my $RegenPercent = 10; # Set Regen Percent per tic here
    if ($client) {
      my $HPRatio = $client->GetHPRatio();
      if ($HPRatio < 100) {
        my $HPMax = $client->GetMaxHP();
        my $HPNew = (($HPRatio + $RegenPercent) / 100) * $HPMax;
        $client->SetHP($HPNew);
      }
      my $ManaRatio = $client->GetManaRatio();
      if ($ManaRatio < 100) {
        my $ManaMax = $client->GetMaxMana();
        my $ManaNew = (($ManaRatio + $RegenPercent) / 100) * $ManaMax;
        $client->SetMana($ManaNew);
      }
      my $EnduranceRatio = $client->GetEnduranceRatio();
      if ($EnduranceRatio < 100) {
        my $EnduranceMax = $client->GetMaxEndurance();
        my $EnduranceNew = (($EnduranceRatio + $RegenPercent) / 100) * $EnduranceMax;
        $client->SetEndurance($EnduranceNew);
      }
      quest::settimer("DoRegen", 6);
    }
  }
}

sub EVENT_POPUPRESPONSE {
  if ($popupid == 666) { #hateplaneb
    quest::movepc(186,-393,656,3);
  }
  if ($popupid == 674) { #airplane
    quest::movepc(71,539,1384,-664);
  }
  if ($popupid == 15891) { #dragonscale
    #quest::movepc(442,-1954,3916,19);
  }
  if ($popupid == 2708) { #northkarana
    quest::movepc(13,1209,-3685,-5);
  }
  if ($popupid == 4176) { #ecommons
    quest::movepc(22,-140,-1520,3);
  }
  if ($popupid == 534) { #lavastorm
    quest::movepc(27,460,460,-86);
  }
  if ($popupid == 2707) { #tox
    quest::movepc(38,-916,-1510,-33);
  }
  if ($popupid == 2706) { #gfaydark
    quest::movepc(54,-441,-2023,4);
  }
  if ($popupid == 2709) { #dreadlands
    quest::movepc(86,9658,3047,1052);
  }
  if ($popupid == 2284) { #iceclad
    quest::movepc(110,385,5321,-17);
  }
  if ($popupid == 2031) { #coboltscar
    quest::movepc(117,-1634,-1065,299);
  }
  if ($popupid == 3615) { #twilight
    quest::movepc(170,-1028,1338,39);
  }
  if ($popupid == 3794) { #stonebrunt
    quest::movepc(100,673,-4531,0);
  }
  if ($popupid == 6180) { #wallofslaughter
    #quest::movepc(300,-943,13,130);
  }
  if ($popupid == 5733) { #barindu
    quest::movepc(283,209,-515,-119);
  }
  if ($popupid == 8237) { #eastkorlach
    #quest::movepc(362,-750,-1002,48);
  }
  if ($popupid == 8967) { #arcstone
    #quest::movepc(369,1630,-279,5);
  }
  if ($popupid == 999) { #mesa
    #quest::movepc(397,-85,-2050,19);
  }
  if ($popupid == 1000) { #guild banner
    #not implemented yet
  }
  if ($popupid == 416) { #kattacastrum
    #quest::movepc(416,-2,-425,-19);
  }
  if ($popupid == 20543) { #potimea
    quest::movepc(219,0,110,8);
  }
  if ($popupid == 21986) { #brellsrest
    #quest::movepc(480,-23,-619,36);
  }
}

sub EVENT_CLICKDOOR
{
# This will move RoF clients to their instance, the rest are handled in the DB
  if (($client->GetClientVersionBit() & 4294967264) != 0) {
    if ($doorid == 2 || $doorid == 5) {
        quest::MovePCInstance(344, 5, 0, 588, 1.75, 130);
    }
  }
}

I wanted to change drop percentage of quest items on Castlen's PoK quest Desert Crawl so it would not take forever with 6 chars so here is code for that.

Add more Spider Poison Sacs and ScarabEggs
Code:
REPLACE INTO `lootdrop_entries` (`lootdrop_id`, `item_id`, `item_charges`, `equip_item`, `chance`, `disabled_chance`, `trivial_min_level`, `trivial_max_level`, `multiplier`, `npc_min_level`, `npc_max_level`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (11691, 14018, 1, 0, 100, 0, 0, 0, 4, 0, 0, -1, -1, NULL, NULL);
REPLACE INTO `lootdrop_entries` (`lootdrop_id`, `item_id`, `item_charges`, `equip_item`, `chance`, `disabled_chance`, `trivial_min_level`, `trivial_max_level`, `multiplier`, `npc_min_level`, `npc_max_level`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (90724, 13262, 1, 0, 100, 0, 0, 0, 1, 0, 0, -1, -1, NULL, NULL);
 
This is a fascinating look under the hood!

Re: your first rule - so the client will automatically flag someone if they target something using MQ? I had thought that was something a GM would need to personally observe. Guess not!
 
This is a fascinating look under the hood!

Re: your first rule - so the client will automatically flag someone if they target something using MQ? I had thought that was something a GM would need to personally observe. Guess not!

Yep, that is why you will see on other threads RG recommends not using /target unless id is close by. Until I looked under hood myself that is something I also did not know.
 
Yep, that is why you will see on other threads RG recommends not using /target unless id is close by. Until I looked under hood myself that is something I also did not know.
I dont think that works how you think it does. I can target something of xtar all the way across zone, well outside clip plane (witch is also a local setting).
 
I dont think that works how you think it does. I can target something of xtar all the way across zone, well outside clip plane (witch is also a local setting).

Selecting a group member or an Xtarget is not the same as using /target command or right clicking an NPC on the map correct?
 
Selecting a group member or an Xtarget is not the same as using /target command or right clicking an NPC on the map correct?
You can target mobs (xtar) or assist target all the way across zones. I dont know how EQ "sees" those commands any different, thats why I am questioning if that line does what you think it does (not saying your wrong, just saying that makes no sense to me).

the /tar npc (EQ command) only works in clip plane/set range, but if my friend zones in, and gets agro, i can target the mobs on xtar to see he has agro.
 
You can target mobs (xtar) or assist target all the way across zones. I dont know how EQ "sees" those commands any different, thats why I am questioning if that line does what you think it does (not saying your wrong, just saying that makes no sense to me).

the /tar npc (EQ command) only works in clip plane/set range, but if my friend zones in, and gets agro, i can target the mobs on xtar to see he has agro.
With MQ though the /tar npc command works zone-wide.
 
Thought I would add this one to the list, if you want original sleeper pre-awaken, the below query will get you there.



Sleeper
Code:
update spawn_conditions set value = 1 where id = 1 and zone = 'sleeper';
update spawn_conditions set value = 0 where id = 2 and zone = 'sleeper';
update spawn_condition_values set value = 1 where id = 1 and zone = 'sleeper';
update spawn_condition_values set value = 0 where id = 2 and zone = 'sleeper';
delete from respawn_times where id = '25250';
delete from respawn_times where id = '58546';
delete from respawn_times where id = '58547';
delete from respawn_times where id = '58548';
delete from respawn_times where id = '58549';
delete from quest_globals where name = 'kerafyrm';
 
You can target mobs (xtar) or assist target all the way across zones. I dont know how EQ "sees" those commands any different, thats why I am questioning if that line does what you think it does (not saying your wrong, just saying that makes no sense to me).

the /tar npc (EQ command) only works in clip plane/set range, but if my friend zones in, and gets agro, i can target the mobs on xtar to see he has agro.

He is correct. Xtar targeting utilizes a different packet than /tar which is how we can detect if you are using MQ2 to target outside the client’s normal range.

Kinglykrab and I open-sourced a decent amount of anticheat measures after we closed our server a few years ago. We added warp detection that utilizes the packet and methods Live uses as well as some smaller stuff like breaking fartaunt, instant spell scribing, etc.

Basically everything we could add server side. We were also DLL injecting the client and had a lot more aggressive methods for anticheat. Though only a few servers do this (P99, Quarm mainly at the moment) emu servers can have much more aggressive detection than Live. On these servers being careful about targeting isn’t going to make a difference.

This is a nice little collection of queries for newer people trying to run something for themselves or their families. I’d recommend downloading something like Navicat and just taking a scroll through the rule_values table. There are many very simple modifications we’ve set up that can be done with 0 SQL or Perl/Lua knowledge.

Edit: For the queries in the main post I would change them to not set ruleset id to 1 and make it change the value of a rule WHERE ruleset id = 1. There are multiple rulesets by default for a reason and you will run into issues later on with this.
 
Last edited:
Other - Server Code and Tips For Those Running Own Server

Users who are viewing this thread

Back
Top
Cart