Some Map enhancements for /highlight
Posted: Sat Dec 26, 2015 8:37 pm
Just wanted to share some tweaks I made to MQ2Map that some may find useful.
1) /high size ##
This changes the size of your highlights. Default value is 100.
2) /high pulse
This toggles pulsing highlights, which makes them stick out way easier. The pulse changes the size of the marker between 50% - 150% of the normal size. The pulsing is really an elegant looking thing, I really enjoy it since I added it, please check it out and let me know what you think.
Both of these settings are default to the standard map settings, so new users won't experience them unless set explicitly.
I also made it so these settings will persist in your MQ2Map.ini file.
Also please note, I'm not using the vanilla version of MQ2Map, so the parts I changed will probably just need to be plugged into the vanilla version, I assume it'll be easy. These changes aren't hard and I'm not a professional C++ dev.
MQ2Map.cpp
MQ2Map.h
MQ2MapCommands.cpp
1) /high size ##
This changes the size of your highlights. Default value is 100.
2) /high pulse
This toggles pulsing highlights, which makes them stick out way easier. The pulse changes the size of the marker between 50% - 150% of the normal size. The pulsing is really an elegant looking thing, I really enjoy it since I added it, please check it out and let me know what you think.
Both of these settings are default to the standard map settings, so new users won't experience them unless set explicitly.
I also made it so these settings will persist in your MQ2Map.ini file.
Also please note, I'm not using the vanilla version of MQ2Map, so the parts I changed will probably just need to be plugged into the vanilla version, I assume it'll be easy. These changes aren't hard and I'm not a professional C++ dev.
MQ2Map.cpp
Code: Select all
// MQ2Map.cpp : Defines the entry point for the DLL application.
//
// PLUGIN_API is only to be used for callbacks. All existing callbacks at this time
// are shown below. Remove the ones your plugin does not use. Always use Initialize
// and Shutdown for setup and cleanup, do NOT do it in DllMain.
#include "../MQ2Plugin.h"
#include "MQ2Map.h"
PreSetup("MQ2Map");
long repeatLast = 0;
long repeatInterval = 10;
clock_t highPulseRepeatLast = clock();
long highPulseRepeatIntervalMillis = 50;
unsigned long bmMapRefresh = 0;
BOOL repeatMaphide = FALSE;
BOOL repeatMapshow = FALSE;
DWORD HighlightColor=0xFF700070;
DWORD HighlightSIDELEN = 100;
BOOL HighlightPulse = FALSE;
BOOL HighlightPulseIncreasing = TRUE;
int HighlightPulseIndex = 0;
DWORD HighlightPulseDiff = HighlightSIDELEN / 10;
CHAR MapSpecialClickString[16][MAX_STRING]=
{
"",// unused, will always target
"",//SHIFT
"/maphide id %i",//CTRL
"",//CTRL|SHIFT
"/highlight id %i",//LALT
"",//LALT|SHIFT
"",//LALT|CTRL
"",//LALT|SHIFT|CTRL
"",//RALT
"",//RALT|SHIFT
"",//RALT|CTRL
"",//RALT|SHIFT|CTRL
"",//RALT|LALT
"",//RALT|LALT|SHIFT
"",//RALT|LALT|CTRL
"" //RALT|LALT|SHIFT|CTRL
};
CHAR MapNameString[MAX_STRING]={"%N"};
CHAR MapTargetNameString[MAX_STRING]={"%N"};
CHAR mapshowStr[MAX_STRING] = {""};
CHAR maphideStr[MAX_STRING] = {""};
SEARCHSPAWN MapFilterCustom = {0};
SEARCHSPAWN MapFilterNamed = {0};
MAPFILTER MapFilterOptions[] = {
{"All", TRUE,-1, TRUE,MAPFILTER_Invalid,TRUE, "Enables/disables map functions"},
{"PC", FALSE,0xFF00FF, TRUE,MAPFILTER_All,TRUE, "Displays PCs"},
{"PCConColor", FALSE,-1, TRUE,MAPFILTER_PC,FALSE, "Displays PCs in consider colors"},
{"Group", FALSE,0x0080C0, TRUE,MAPFILTER_PC,FALSE, "Displays group members in a specific color"},
{"Mount", FALSE,0x707070, TRUE,MAPFILTER_All,TRUE, "Displays mounts"},
{"NPC", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays NPCs"},
{"NPCConColor", FALSE,-1, TRUE,MAPFILTER_NPC,FALSE, "Displays NPCs in consider colors"},
{"Untargetable", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays Untargetable NPCs"},
{"Pet", FALSE,0x707070, TRUE,MAPFILTER_All,TRUE, "Displays pets"},
{"Corpse", FALSE,0x00C000, TRUE,MAPFILTER_All,TRUE, "Displays corpses"},
{"Chest", FALSE,0xC08000, TRUE,MAPFILTER_All,TRUE, "Displays chestesses"},
{"Trigger", FALSE,0xC08000, TRUE,MAPFILTER_All,TRUE, "Displays hidden triggers"},
{"Trap", FALSE,0xC08000, TRUE,MAPFILTER_All,TRUE, "Displays hidden traps"},
{"Timer", FALSE,0xC08000, TRUE,MAPFILTER_All,TRUE, "Displays hidden timers"},
{"Ground", FALSE,0xC0C0C0, TRUE,MAPFILTER_All,TRUE, "Displays ground items"},
{"Target", FALSE,0xC00000, TRUE,MAPFILTER_All,FALSE, "Displays your target"},
{"TargetLine", FALSE,0x808080, TRUE,MAPFILTER_Target,FALSE, "Displays a line to your target"},
{"TargetRadius", FALSE,0x808080, FALSE,MAPFILTER_Target,FALSE, "Sets radius of a circle around your target to # (omit or set to 0 to disable)"},
{"TargetMelee", FALSE,0xFF8080, FALSE,MAPFILTER_Target,FALSE, "Draws a melee-range circle around your target"},
{"Vector", FALSE,-1, TRUE,MAPFILTER_All,TRUE, "Displays heading vectors"},
{"Custom", FALSE,-1, FALSE,MAPFILTER_All,TRUE, "Sets custom filter (omit to disable)"},
{"CastRadius", FALSE,0x808080, FALSE,MAPFILTER_All,FALSE, "Sets radius of casting circle to # (omit or set to 0 to disable)"},
{"NormalLabels", 0,-1, TRUE,MAPFILTER_Invalid,FALSE, "Toggles non-MQ2 label display"},
{"Menu", FALSE,-1, TRUE,MAPFILTER_Invalid,FALSE, "Allows display of right-click context menu"},
{"SpellRadius", FALSE,0x00C000, FALSE,MAPFILTER_All,FALSE, "Sets radius of 2nd casting circle to # (omit or set to 0 to disable)"},
{"Aura", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays Auras"},
{"Object", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays inanimate objects"},
{"Banner", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays banners"},
{"Campfire", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays campfires"},
{"PCCorpse", FALSE,0x00C000, TRUE,MAPFILTER_All,TRUE, "Displays PC corpses, when corpse setting is on"},
{"NPCCorpse", FALSE,0x00C000, TRUE,MAPFILTER_All,TRUE, "Displays NPC corpses, when corpse setting is on"},
{"Mercenary", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays mercenaries"},
{"Named", FALSE,0x404040, TRUE,MAPFILTER_All,TRUE, "Displays named NPCs"},
{"Marker", FALSE,-1, FALSE,MAPFILTER_All,TRUE, "Displays marker (mobtype triangle/square/diamond size)"},
{"TargetPath", FALSE,-1, TRUE,MAPFILTER_Target,FALSE, "Draws EQ Path to selected target"},
{NULL, FALSE,-1, FALSE,MAPFILTER_Invalid,FALSE, NULL}
};
PCSIDLWNDVFTABLE CMyMapViewWnd__OldvfTable=0;
PCSIDLWNDVFTABLE MapViewMap_OldvfTable=0;
DWORD CMyMapViewWnd__OldDestructor=0;
DWORD CMyMapViewWnd__OldHandleRButtonDown=0;
DWORD CMyMapViewWnd__OldPostDraw=0;
DWORD MapViewMap__OldHandleRButtonDown=0;
DWORD __declspec(naked) CMyMapViewWnd__Destructor(const BOOL Deallocate)
{
__asm {
push ecx;
push eax;
}
if (CMyMapViewWnd__OldvfTable && MapViewMap_OldvfTable) {
// make our own little stack frame here
// operator delete assumes that it is there
// it uses (unnecessarily) ebp-4
__asm {
push ebp
push eax
push eax
mov ebp, esp
}
delete pMapViewWnd->pvfTable;
pMapViewWnd->pvfTable=CMyMapViewWnd__OldvfTable;
CMyMapViewWnd__OldvfTable = NULL;
delete ((PEQMAPWINDOW)pMapViewWnd)->pMapViewMapVfTable;
((PEQMAPWINDOW)pMapViewWnd)->pMapViewMapVfTable = MapViewMap_OldvfTable;
MapViewMap_OldvfTable = NULL;
__asm {
pop eax
pop eax
pop ebp
}
}
__asm {
pop eax;
pop ecx;
jmp [CMyMapViewWnd__OldDestructor];
}
}
bool RButtonDown()
{
if (pCurrentMapLabel)
{
return MapSelectTarget();
}
if (!IsOptionEnabled(MAPFILTER_ContextMenu))
return false;
return true;
}
VOID __declspec(naked) MapViewMap__HandleRButtonDown(DWORD point, DWORD unknown)
{
__asm {
push ecx;
push eax;
}
if (RButtonDown())
{
__asm {
pop eax;
pop ecx;
jmp [MapViewMap__OldHandleRButtonDown];
};
}
else
{
__asm {
pop eax;
pop ecx;
xor eax, eax;
retn 8;
}
}
}
VOID __declspec(naked) CMyMapViewWnd__PostDraw()
{
__asm {
push esi;
mov esi, ecx;
call [MapUpdate];
call [MapAttach];
mov ecx, esi;
call [CMyMapViewWnd__OldPostDraw];
push eax;
call [MapDetach];
pop eax;
mov ecx, esi;
pop esi;
ret;
};
}
class CMyMapViewWnd
{
public:
DWORD Constructor_Trampoline(class CXWnd *);
DWORD Constructor_Detour(class CXWnd *wnd)
{
CMapViewWnd *pWnd=(CMapViewWnd*)this;
DWORD Ret=Constructor_Trampoline(wnd);
PCSIDLWNDVFTABLE pvfTable = new CSIDLWNDVFTABLE;
PCSIDLWNDVFTABLE pMapViewMapVfTable = new CSIDLWNDVFTABLE;
*pvfTable=*pWnd->pvfTable;
*pMapViewMapVfTable=*((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable;
CMyMapViewWnd__OldvfTable=pWnd->pvfTable;
pWnd->pvfTable=pvfTable;
MapViewMap_OldvfTable=((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable=pMapViewMapVfTable;
CMyMapViewWnd__OldPostDraw=(DWORD)((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->PostDraw2;
CMyMapViewWnd__OldDestructor=(DWORD)pWnd->pvfTable->vector_deleting_destructor;
pWnd->pvfTable->vector_deleting_destructor=CMyMapViewWnd__Destructor;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->PostDraw2=CMyMapViewWnd__PostDraw;
MapViewMap__OldHandleRButtonDown=(DWORD)((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->HandleRButtonDown;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->HandleRButtonDown=MapViewMap__HandleRButtonDown;
return Ret;
}
static void StealVFTable()
{
if (CMapViewWnd *pWnd=(CMapViewWnd*)pMapViewWnd)
{
PCSIDLWNDVFTABLE pvfTable = new CSIDLWNDVFTABLE;
PCSIDLWNDVFTABLE pMapViewMapVfTable = new CSIDLWNDVFTABLE;
*pvfTable=*pWnd->pvfTable;
*pMapViewMapVfTable=*((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable;
CMyMapViewWnd__OldvfTable=pWnd->pvfTable;
pWnd->pvfTable=pvfTable;
MapViewMap_OldvfTable=((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable=pMapViewMapVfTable;
CMyMapViewWnd__OldPostDraw=(DWORD)((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->PostDraw2;
CMyMapViewWnd__OldDestructor=(DWORD)pWnd->pvfTable->vector_deleting_destructor;
pWnd->pvfTable->vector_deleting_destructor=CMyMapViewWnd__Destructor;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->PostDraw2=CMyMapViewWnd__PostDraw;
MapViewMap__OldHandleRButtonDown=(DWORD)((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->HandleRButtonDown;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable->HandleRButtonDown=MapViewMap__HandleRButtonDown;
}
}
static void RestoreVFTable()
{
if (CMapViewWnd *pWnd=(CMapViewWnd*)pMapViewWnd)
{
if (CMyMapViewWnd__OldvfTable && MapViewMap_OldvfTable) {
delete pWnd->pvfTable;
pWnd->pvfTable=CMyMapViewWnd__OldvfTable;
delete ((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable;
((PEQMAPWINDOW)pWnd)->pMapViewMapVfTable = MapViewMap_OldvfTable;
}
}
}
};
DETOUR_TRAMPOLINE_EMPTY(DWORD CMyMapViewWnd::Constructor_Trampoline(class CXWnd *));
bool Update=true;
#ifndef ISXEQ
// Called once, when the plugin is to initialize
PLUGIN_API VOID InitializePlugin(VOID)
{
DebugSpewAlways("Initializing MQ2Map");
bmMapRefresh=AddMQ2Benchmark("Map Refresh");
unsigned long i;
CHAR szBuffer[MAX_STRING]={0};
CHAR tmp_1[MAX_STRING] = {0};
CHAR tmp_2[MAX_STRING] = {0};
for (i=0;MapFilterOptions[i].szName;i++) {
sprintf(szBuffer,"%s-Color",MapFilterOptions[i].szName);
MapFilterOptions[i].Enabled = GetPrivateProfileInt("Map Filters",MapFilterOptions[i].szName,MapFilterOptions[i].Default,INIFileName);
MapFilterOptions[i].Color = GetPrivateProfileInt("Map Filters",szBuffer,MapFilterOptions[i].DefaultColor,INIFileName) | 0xFF000000;
sprintf(tmp_1,"%s-Size",MapFilterOptions[i].szName);
GetPrivateProfileString("Marker Filters",MapFilterOptions[i].szName,"None",tmp_2,MAX_STRING,INIFileName);
DWORD mark = FindMarker(tmp_2);
if (mark == 99) mark = 0;
MapFilterOptions[i].Marker = mark;
MapFilterOptions[i].MarkerSize = GetPrivateProfileInt("Marker Filters",tmp_1,0,INIFileName);
}
repeatMapshow = GetPrivateProfileInt("Map Filters","Mapshow-Repeat",FALSE,INIFileName);
repeatMaphide = GetPrivateProfileInt("Map Filters","Maphide-Repeat",FALSE,INIFileName);
HighlightSIDELEN = GetPrivateProfileInt("Map Filters", "HighSize", HighlightSIDELEN, INIFileName);
HighlightPulse = GetPrivateProfileInt("Map Filters", "HighPulse", HighlightPulse, INIFileName);
GetPrivateProfileString("Map Filters","Mapshow","",mapshowStr,MAX_STRING,INIFileName);
GetPrivateProfileString("Map Filters","Maphide","",maphideStr,MAX_STRING,INIFileName);
MapInit();
GetPrivateProfileString("Naming Schemes","Normal","%N",MapNameString,MAX_STRING,INIFileName);
GetPrivateProfileString("Naming Schemes","Target","%N",MapTargetNameString,MAX_STRING,INIFileName);
for (i=1;i<16;i++)
{
sprintf(szBuffer,"KeyCombo%d",i);
GetPrivateProfileString("Right Click",szBuffer,MapSpecialClickString[i],MapSpecialClickString[i],MAX_STRING,INIFileName);
}
// Do not use Custom, since the string isn't stored
MapFilterOptions[MAPFILTER_Custom].Enabled = 0;
AddCommand("/mapfilter",MapFilters,0,1,1);
AddCommand("/maphide",MapHideCmd,0,1,1);
AddCommand("/mapshow",MapShowCmd,0,1,1);
AddCommand("/highlight",MapHighlightCmd,0,1,1);
AddCommand("/mapnames",MapNames,0,1,1);
AddCommand("/mapclick",MapClickCommand,0,1,0);
EzDetour(CMapViewWnd__CMapViewWnd,&CMyMapViewWnd::Constructor_Detour,&CMyMapViewWnd::Constructor_Trampoline);
CMyMapViewWnd::StealVFTable();
AddMQ2Data("MapSpawn",dataMapSpawn);
ClearSearchSpawn(&MapFilterNamed);
ParseSearchSpawn("#", &MapFilterNamed);
}
// Called once, when the plugin is to shutdown
PLUGIN_API VOID ShutdownPlugin(VOID)
{
DebugSpewAlways("Shutting down MQ2Map");
Update=false;
RemoveMQ2Data("MapSpawn");
RemoveDetour(CMapViewWnd__CMapViewWnd);
MapClear();
CMyMapViewWnd::RestoreVFTable();
RemoveMQ2Benchmark(bmMapRefresh);
RemoveCommand("/maphide");
RemoveCommand("/mapshow");
RemoveCommand("/mapfilter");
RemoveCommand("/highlight");
RemoveCommand("/mapnames");
RemoveCommand("/mapclick");
}
// This is called every time MQ pulses
PLUGIN_API VOID OnPulse(VOID)
{
// DONT leave in this debugspew, even if you leave in all the others
// DebugSpewAlways("MQ2Mapshow::OnPulse()");
long curTime = MakeTime();
clock_t curClockTime = clock();
bool cleared = false;
CHAR szBuffer[MAX_STRING] = {0};
if (curClockTime > highPulseRepeatLast + highPulseRepeatIntervalMillis && HighlightPulse)
{
if (HighlightPulseIndex == 5 || HighlightPulseIndex == -5)
HighlightPulseIncreasing = !HighlightPulseIncreasing;
if (HighlightPulseIncreasing)
HighlightPulseIndex++;
else
HighlightPulseIndex--;
highPulseRepeatLast = curClockTime;
}
if (curTime > repeatLast + repeatInterval) {
if (repeatMapshow && strlen(mapshowStr) > 0) {
if (!cleared) {
MapClear();
MapGenerate();
cleared = true;
}
SEARCHSPAWN ss;
ClearSearchSpawn(&ss);
ParseSearchSpawn(mapshowStr,&ss);
MapShow(ss);
}
if (repeatMaphide && strlen(maphideStr) > 0) {
if (!cleared) {
MapClear();
MapGenerate();
cleared = true;
}
SEARCHSPAWN ss;
ClearSearchSpawn(&ss);
ParseSearchSpawn(maphideStr,&ss);
MapHide(ss);
}
repeatLast = curTime;
}
}
// This is called each time a spawn is added to a zone (inserted into EQ's list of spawns),
// or for each existing spawn when a plugin first initializes
// NOTE: When you zone, these will come BEFORE OnZoned
PLUGIN_API VOID OnAddSpawn(PSPAWNINFO pNewSpawn)
{
// your toon's spawn id changes and it's no longer zero to start
// don't added it all
if (Update && pNewSpawn->SpawnID != 0 && GetCharInfo()->pSpawn != pNewSpawn) {
DebugSpewAlways("MQ2Map::OnAddSpawn(%s) = %d",pNewSpawn->Name, pNewSpawn->SpawnID);
AddSpawn(pNewSpawn);
}
}
// This is called each time a spawn is removed from a zone (removed from EQ's list of spawns).
// It is NOT called for each existing spawn when a plugin shuts down.
PLUGIN_API VOID OnRemoveSpawn(PSPAWNINFO pSpawn)
{
DebugSpewAlways("MQ2Map::OnRemoveSpawn(%s) = %d",pSpawn->Name, pSpawn->SpawnID);
if (Update)
RemoveSpawn(pSpawn);
}
PLUGIN_API VOID SetGameState(DWORD GameState)
{
if (GameState==3)
{
MapClear();
}
}
// This is called each time a ground item is added to a zone
// or for each existing ground item when a plugin first initializes
// NOTE: When you zone, these will come BEFORE OnZoned
PLUGIN_API VOID OnAddGroundItem(PGROUNDITEM pNewGroundItem)
{
DebugSpewAlways("MQ2Map::OnAddGroundItem(%d)",pNewGroundItem->DropID);
if (Update)
AddGroundItem(pNewGroundItem);
}
// This is called each time a ground item is removed from a zone
// It is NOT called for each existing ground item when a plugin shuts down.
PLUGIN_API VOID OnRemoveGroundItem(PGROUNDITEM pGroundItem)
{
DebugSpewAlways("MQ2Map::OnRemoveGroundItem(%d)",pGroundItem->DropID);
if (Update)
RemoveGroundItem(pGroundItem);
}
PLUGIN_API PMAPLINE MQ2MapAddLine() {
return InitLine();
}
PLUGIN_API VOID MQ2MapDeleteLine(PMAPLINE pLine) {
DeleteLine(pLine);
}
#endif
Code: Select all
#include <map>
using namespace std;
#ifdef ISXEQ
#include "ISXEQMap.h"
#endif
#define MAPFILTER_All 0
#define MAPFILTER_PC 1
#define MAPFILTER_PCConColor 2
#define MAPFILTER_Group 3
#define MAPFILTER_Mount 4
#define MAPFILTER_NPC 5
#define MAPFILTER_NPCConColor 6
#define MAPFILTER_Untargetable 7
#define MAPFILTER_Pet 8
#define MAPFILTER_Corpse 9
#define MAPFILTER_Chest 10
#define MAPFILTER_Trigger 11
#define MAPFILTER_Trap 12
#define MAPFILTER_Timer 13
#define MAPFILTER_Ground 14
#define MAPFILTER_Target 15
#define MAPFILTER_TargetLine 16
#define MAPFILTER_TargetRadius 17
#define MAPFILTER_TargetMelee 18
#define MAPFILTER_Vector 19
#define MAPFILTER_Custom 20
#define MAPFILTER_CastRadius 21
#define MAPFILTER_NormalLabels 22
#define MAPFILTER_ContextMenu 23
#define MAPFILTER_SpellRadius 24
#define MAPFILTER_Aura 25
#define MAPFILTER_Object 26
#define MAPFILTER_Banner 27
#define MAPFILTER_Campfire 28
#define MAPFILTER_PCCorpse 29
#define MAPFILTER_NPCCorpse 30
#define MAPFILTER_Mercenary 31
#define MAPFILTER_Named 32
#define MAPFILTER_TargetPath 33
#define MAPFILTER_Marker 34
#define MAPFILTER_NUMBER 35
#define MAPFILTER_Invalid (-1)
// normal labels
typedef struct _MAPFILTER {
PCHAR szName;
//DWORD Index;
DWORD Default;
DWORD DefaultColor;
BOOL bIsToggle;
DWORD RequiresOption;
BOOL RegenerateOnChange;
PCHAR szHelpString;
DWORD Marker;
DWORD MarkerSize;
DWORD Enabled;
DWORD Color;
} MAPFILTER, *PMAPFILTER;
extern unsigned long bmMapRefresh;
extern DWORD HighlightColor;
extern DWORD HighlightSIDELEN;
extern BOOL HighlightPulse;
extern BOOL HighlightPulseIncreasing;
extern int HighlightPulseIndex;
extern DWORD HighlightPulseDiff;
extern CHAR MapNameString[MAX_STRING];
extern CHAR MapTargetNameString[MAX_STRING];
extern CHAR mapshowStr[MAX_STRING];
extern CHAR maphideStr[MAX_STRING];
extern SEARCHSPAWN MapFilterCustom;
extern SEARCHSPAWN MapFilterNamed;
extern MAPFILTER MapFilterOptions[];
extern CHAR MapSpecialClickString[16][MAX_STRING];
extern BOOL repeatMapshow;
extern BOOL repeatMaphide;
/* COMMANDS */
VOID MapFilters(PSPAWNINFO pChar, PCHAR szLine);
VOID MapFilterSetting(PSPAWNINFO pChar, DWORD nMapFilter, PCHAR szValue=NULL);
VOID MapHighlightCmd(PSPAWNINFO pChar, PCHAR szLine);
VOID PulseReset();
VOID MapHideCmd(PSPAWNINFO pChar, PCHAR szLine);
VOID MapShowCmd(PSPAWNINFO pChar, PCHAR szLine);
VOID MapNames(PSPAWNINFO pChar, PCHAR szLine);
VOID MapClickCommand(PSPAWNINFO pChar, PCHAR szLine);
PCHAR FormatMarker(PCHAR szLine,PCHAR szDest);
DWORD TypeToMapfilter(PSPAWNINFO pChar);
/* API */
VOID MapInit();
VOID MapClear();
VOID MapGenerate();
DWORD MapHighlight(SEARCHSPAWN *pSearch);
DWORD MapHide(SEARCHSPAWN &Search);
DWORD MapShow(SEARCHSPAWN &Search);
VOID MapUpdate();
VOID MapAttach();
VOID MapDetach();
bool MapSelectTarget();
DWORD FindMarker(PCHAR szMark);
long MakeTime();
#ifndef ISXEQ
BOOL dataMapSpawn(PCHAR szIndex, MQ2TYPEVAR &Ret);
#else
bool dataMapSpawn(int argc, char *argv[], LSTYPEVAR &Ret);
#endif
struct _MAPSPAWN* AddSpawn(PSPAWNINFO pNewSpawn,BOOL ExplicitAllow=false);
bool RemoveSpawn(PSPAWNINFO pSpawn);
void AddGroundItem(PGROUNDITEM pGroundItem);
void RemoveGroundItem(PGROUNDITEM pGroundItem);
static inline BOOL IsOptionEnabled(DWORD Option)
{
if (Option==MAPFILTER_Invalid)
return true;
return (MapFilterOptions[Option].Enabled && IsOptionEnabled(MapFilterOptions[Option].RequiresOption));
}
static inline BOOL RequirementsMet(DWORD Option)
{
if (Option==MAPFILTER_Invalid)
return true;
return (IsOptionEnabled(MapFilterOptions[Option].RequiresOption));
}
PLUGIN_API PMAPLINE InitLine();
PLUGIN_API VOID DeleteLine(PMAPLINE pLine);
Code: Select all
#include "../MQ2Plugin.h"
#include "MQ2Map.h"
#ifndef ISXEQ
// ***************************************************************************
// Function: MapFilters
// Description: Our '/mapfilter' command
// Sets map filters
// Usage: /mapfilter [options|help]
// ***************************************************************************
VOID MapFilterSetting(PSPAWNINFO pChar, DWORD nMapFilter, PCHAR szValue)
{
CHAR szBuffer[MAX_STRING] = {0};
CHAR Buff[MAX_STRING]={0};
DWORD dwValue = 0;
PCHAR szFilterMap[] = {
"hide",
"show",
NULL
};
if (!pChar) return;
PMAPFILTER pMapFilter=&MapFilterOptions[nMapFilter];
if (!RequirementsMet(nMapFilter))
{
sprintf(szBuffer,"'%s' requires '%s' option. Please enable this option first.",pMapFilter->szName,MapFilterOptions[pMapFilter->RequiresOption].szName);
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
return;
}
if (!szValue) {
if (pMapFilter->bIsToggle) {
sprintf(szBuffer,"%s: %s",pMapFilter->szName,szFilterMap[pMapFilter->Enabled]);
} else if (nMapFilter == MAPFILTER_Custom) {
if (IsOptionEnabled(nMapFilter)==0) {
sprintf(szBuffer,"%s: Off",pMapFilter->szName);
} else {
sprintf(szBuffer,"%s: %s",pMapFilter->szName,FormatSearchSpawn(Buff,&MapFilterCustom));
}
} else {
sprintf(szBuffer,"%s: %d",pMapFilter->szName,pMapFilter->Enabled);
}
if (pMapFilter->DefaultColor != -1) {
CHAR szBuffer2[MAX_STRING] = {0};
DWORD R,G,B;
R= (pMapFilter->Color&0xFF0000)/0x10000;
G= (pMapFilter->Color&0xFF00)/0x100;
B= pMapFilter->Color&0xFF;
sprintf(szBuffer2,"%s (Color: %d %d %d)",szBuffer,R,G,B);
strcpy(szBuffer,szBuffer2);
}
} else {
if (pMapFilter->bIsToggle) {
if (!stricmp(szFilterMap[0],szValue)) {
pMapFilter->Enabled = 0;
} else if (!stricmp(szFilterMap[1],szValue)) {
pMapFilter->Enabled = 1;
} else {
pMapFilter->Enabled = 1 - pMapFilter->Enabled;
}
sprintf(szBuffer,"%s is now set to: %s",pMapFilter->szName,szFilterMap[IsOptionEnabled(nMapFilter)]);
} else if (nMapFilter == MAPFILTER_Custom) {
ClearSearchSpawn(&MapFilterCustom);
if (szValue[0]==0) {
pMapFilter->Enabled = 0;
sprintf(szBuffer,"%s is now set to: Off",pMapFilter->szName);
} else {
pMapFilter->Enabled = 1;
ParseSearchSpawn(szValue,&MapFilterCustom);
sprintf(szBuffer,"%s is now set to: %s",pMapFilter->szName,FormatSearchSpawn(Buff,&MapFilterCustom));
}
}
else if (nMapFilter == MAPFILTER_Marker) {
CHAR szBuffer2[MAX_STRING] = {0};
GetArg(szBuffer2,szValue,1);
if (!stricmp(szFilterMap[0],szValue)) {
pMapFilter->Enabled = 0;
sprintf(szBuffer,"%s is now set to: %s",pMapFilter->szName,szFilterMap[IsOptionEnabled(nMapFilter)]);
}
else if (!stricmp(szFilterMap[1],szValue)) {
pMapFilter->Enabled = 1;
sprintf(szBuffer,"%s is now set to: %s",pMapFilter->szName,szFilterMap[IsOptionEnabled(nMapFilter)]);
}
else {
pMapFilter->Enabled = 1;
sprintf(szBuffer,"%s %s",pMapFilter->szName,FormatMarker(szValue,Buff));
}
} else {
pMapFilter->Enabled = atoi(szValue);
sprintf(szBuffer,"%s is now set to: %d",pMapFilter->szName,pMapFilter->Enabled);
}
}
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
if (szValue) {
itoa(pMapFilter->Enabled,szBuffer,10);
WritePrivateProfileString("Map Filters",pMapFilter->szName,szBuffer,INIFileName);
}
}
VOID MapFilters(PSPAWNINFO pChar, PCHAR szLine)
{
bRunNextCommand = TRUE;
CHAR szArg[MAX_STRING] = {0};
GetArg(szArg,szLine,1);
PCHAR szRest = GetNextArg(szLine);
CHAR szBuffer[MAX_STRING] = {0};
// Display settings
if (szArg[0]==0) {
WriteChatColor("Map filtering settings:",USERCOLOR_DEFAULT);
WriteChatColor("-----------------------",USERCOLOR_DEFAULT);
for (DWORD i=0;MapFilterOptions[i].szName!=NULL;i++)
if (RequirementsMet(i))
MapFilterSetting(pChar,i);
// Display Help
}
else if (!strnicmp(szArg,"help",4))
{
WriteChatColor("Map filtering options:",USERCOLOR_DEFAULT);
for (DWORD i=0;MapFilterOptions[i].szName!=NULL;i++) {
sprintf(szBuffer,"%s%s: %s",MapFilterOptions[i].szName,(MapFilterOptions[i].bIsToggle)?"":" #",MapFilterOptions[i].szHelpString);
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
}
WriteChatColor("'option' color [r g b]: Set display color for 'option' (Omit to reset to default)",USERCOLOR_DEFAULT);
// Set option
} else {
PMAPFILTER Found = 0;
for (DWORD i=0;MapFilterOptions[i].szName!=NULL;i++) {
if (!stricmp(szArg,MapFilterOptions[i].szName)) {
if (!strnicmp(szRest,"color",5)) {
if (MapFilterOptions[i].DefaultColor == -1) {
sprintf(szBuffer,"Option '%s' does not have a color.",MapFilterOptions[i].szName);
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
} else {
DWORD R,G,B;
CHAR szBuffer2[MAX_STRING] = {0};
GetArg(szArg,szRest,2);
if (szArg[0]==0) {
MapFilterOptions[i].Color = MapFilterOptions[i].DefaultColor;
} else {
R=atoi(szArg);
G=atoi(GetArg(szArg,szRest,3));
B=atoi(GetArg(szArg,szRest,4));
if (R>255) R=255;
if (G>255) G=255;
if (B>255) B=255;
MapFilterOptions[i].Color = R*0x10000 + G*0x100 + B;
}
sprintf(szBuffer,"Option '%s' color set to: %d %d %d",MapFilterOptions[i].szName,R,G,B);
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
itoa(MapFilterOptions[i].Color & 0xFFFFFF,szBuffer,10);
sprintf(szBuffer2,"%s-Color",MapFilterOptions[i].szName);
WritePrivateProfileString("Map Filters",szBuffer2,szBuffer,INIFileName);
MapFilterOptions[i].Color |= 0xFF000000;
}
} else {
MapFilterSetting(pChar,i,szRest);
}
Found=&MapFilterOptions[i];
}
}
if (!Found)
SyntaxError("Usage: /mapfilter [option|help]");
else if (Found->RegenerateOnChange)
{
MapClear();
MapGenerate();
}
}
}
VOID MapHighlightCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR szArg[MAX_STRING] = {0};
CHAR szBuffer[MAX_STRING] = {0};
bRunNextCommand = TRUE;
if (szLine==0 || szLine[0]==0)
{
SyntaxError("Usage: /highlight [reset|spawnfilter|size|pulse|[color # # #]]");
return;
};
GetArg(szArg,szLine,1);
if (!stricmp(szArg,"color"))
{
GetArg(szArg,szLine,2);
if (szLine[0]==0)
{
sprintf(szBuffer,"Highlight color: %d %d %d",(HighlightColor&0x00FF0000)>>16,(HighlightColor&0x0000FF00)>>8,(HighlightColor&0x000000FF));
WriteChatColor(szBuffer);
return;
}
unsigned char R=atoi(szArg);
unsigned char G=atoi(GetArg(szArg,szLine,3));
unsigned char B=atoi(GetArg(szArg,szLine,4));
HighlightColor=0xFF000000 | (R << 16) | (G << 8) | (B);
sprintf(szBuffer,"Highlight color: %d %d %d",R,G,B);
WriteChatColor(szBuffer);
return;
}
else if (!stricmp(szArg,"reset"))
{
MapHighlight(0);
WriteChatColor("Highlighting reset",USERCOLOR_DEFAULT);
return;
}
else if (!stricmp(szArg, "size"))
{
HighlightSIDELEN = strtol(GetArg(szArg, szLine, 2), 0, 0);
PulseReset();
sprintf(szBuffer, "Highlight size: %d", HighlightSIDELEN);
WriteChatColor(szBuffer);
// Write setting to file
char szTest[5];
sprintf_s(szTest, "%d", HighlightSIDELEN);
WritePrivateProfileString("Map Filters", "HighSize", szTest, INIFileName);
return;
}
else if (!stricmp(szArg, "pulse"))
{
HighlightPulse = !HighlightPulse;
PulseReset();
sprintf(szBuffer, "Highlight pulse: %s", HighlightPulse ? "ON" : "OFF");
WriteChatColor(szBuffer);
// Write setting to file
WritePrivateProfileString("Map Filters", "HighPulse", HighlightPulse ? "1" : "0", INIFileName);
return;
}
if (PCHARINFO pCharInfo=GetCharInfo())
{
SEARCHSPAWN ssHighlight;
ClearSearchSpawn(&ssHighlight);
ParseSearchSpawn(szLine,&ssHighlight);
sprintf(szBuffer,"%d mapped spawns highlighted",MapHighlight(&ssHighlight));
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
}
}
VOID PulseReset()
{
HighlightPulseIncreasing = TRUE;
HighlightPulseIndex = 0;
HighlightPulseDiff = HighlightSIDELEN / 10;
}
VOID MapHideCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR szArg[MAX_STRING] = {0};
CHAR szBuffer[MAX_STRING] = {0};
bRunNextCommand = TRUE;
if (szLine==0 || szLine[0]==0)
{
SyntaxError("Usage: /maphide [spawnfilter|reset|repeat]");
return;
};
GetArg(szArg,szLine,1);
if (!stricmp(szArg,"reset"))
{
MapClear();
MapGenerate();
WriteChatColor("Map spawns regenerated",USERCOLOR_DEFAULT);
return;
}
if (!stricmp(szArg,"repeat"))
{
if (repeatMaphide)
repeatMaphide = FALSE;
else
repeatMaphide = TRUE;
itoa(repeatMaphide,szBuffer,10);
WritePrivateProfileString("Map Filters","Maphide-Repeat",szBuffer,INIFileName);
sprintf(szBuffer,"maphide repeat set to: %s",(repeatMaphide ? "on" : "off"));
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
return;
}
if (PCHARINFO pCharInfo=GetCharInfo())
{
SEARCHSPAWN ssHide;
ClearSearchSpawn(&ssHide);
ParseSearchSpawn(szLine,&ssHide);
sprintf(szBuffer,"%d mapped spawns hidden",MapHide(ssHide));
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
}
}
VOID MapShowCmd(PSPAWNINFO pChar, PCHAR szLine)
{
CHAR szArg[MAX_STRING] = {0};
CHAR szBuffer[MAX_STRING] = {0};
bRunNextCommand = TRUE;
if (szLine==0 || szLine[0]==0)
{
SyntaxError("Usage: /mapshow [spawnfilter|reset|repeat]");
return;
};
GetArg(szArg,szLine,1);
if (!stricmp(szArg,"reset"))
{
MapClear();
MapGenerate();
WriteChatColor("Map spawns regenerated");
return;
}
if (!stricmp(szArg,"repeat"))
{
if (repeatMapshow)
repeatMapshow = FALSE;
else
repeatMapshow = TRUE;
itoa(repeatMapshow,szBuffer,10);
WritePrivateProfileString("Map Filters","Mapshow-Repeat",szBuffer,INIFileName);
sprintf(szBuffer,"mapshow repeat set to: %s",(repeatMapshow ? "on" : "off"));
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
return;
}
if (PCHARINFO pCharInfo=GetCharInfo())
{
SEARCHSPAWN ssShow;
ClearSearchSpawn(&ssShow);
ParseSearchSpawn(szLine,&ssShow);
sprintf(szBuffer,"%d previously hidden spawns shown",MapShow(ssShow));
WriteChatColor(szBuffer,USERCOLOR_DEFAULT);
}
}
VOID MapNames(PSPAWNINFO pChar, PCHAR szLine)
{
bRunNextCommand = TRUE;
CHAR szOut[MAX_STRING]={0};
if (!szLine[0])
{
sprintf(szOut,"Normal naming string: %s",MapNameString);
WriteChatColor(szOut,USERCOLOR_DEFAULT);
sprintf(szOut,"Target naming string: %s",MapTargetNameString);
WriteChatColor(szOut,USERCOLOR_DEFAULT);
return;
}
CHAR szArg[MAX_STRING] = {0};
GetArg(szArg,szLine,1);
PCHAR szRest = GetNextArg(szLine);
if (!stricmp(szArg,"target"))
{
if (!stricmp(szRest,"reset"))
strcpy(MapTargetNameString,"%N");
else
strcpy(MapTargetNameString,szRest);
sprintf(szOut,"Target naming string: %s",MapTargetNameString);
WriteChatColor(szOut,USERCOLOR_DEFAULT);
WritePrivateProfileString("Naming Schemes","Target",MapTargetNameString,INIFileName);
MapClear();
MapGenerate();
}
else if (!stricmp(szArg,"normal"))
{
if (!stricmp(szRest,"reset"))
strcpy(MapNameString,"%N");
else
strcpy(MapNameString,szRest);
sprintf(szOut,"Normal naming string: %s",MapNameString);
WriteChatColor(szOut,USERCOLOR_DEFAULT);
WritePrivateProfileString("Naming Schemes","Normal",MapNameString,INIFileName);
MapClear();
MapGenerate();
}
else
{
SyntaxError("Usage: /mapnames <target|normal> [value|reset]");
}
}
#endif
PCHAR DescribeCombo(DWORD Combo)
{
static char Description[256];
Description[0]=0;
int pos=0;
if (Combo&XKF_SHIFT)
{
strcpy(&Description[pos],"shift");
pos+=5;
}
if (Combo&XKF_CTRL)
{
if (pos)
{
Description[pos]='+';
pos++;
}
strcpy(&Description[pos],"ctrl");
pos+=4;
}
if (Combo&XKF_LALT)
{
if (pos)
{
Description[pos]='+';
pos++;
}
strcpy(&Description[pos],"lalt");
pos+=4;
}
if (Combo&XKF_RALT)
{
if (pos)
{
Description[pos]='+';
pos++;
}
strcpy(&Description[pos],"ralt");
}
if (!Description[0])
{
return "Invalid";
}
return &Description[0];
}
DWORD ParseCombo(PCHAR Combo)
{
DWORD Ret=0;
if (!Combo || !Combo[0])
return 0;
CHAR Copy[MAX_STRING];
strcpy(Copy,Combo);
Combo=strtok(Copy,"+");
while(Combo)
{
if (!stricmp(Combo,"ctrl"))
Ret+=XKF_CTRL;
else if (!stricmp(Combo,"shift"))
Ret+=XKF_SHIFT;
else if (!stricmp(Combo,"lalt"))
Ret+=XKF_LALT;
else if (!stricmp(Combo,"ralt"))
Ret+=XKF_RALT;
else if (!stricmp(Combo,"alt"))
Ret+=XKF_LALT;
Combo=strtok(NULL,"+");
}
return Ret;
}
#ifndef ISXEQ
VOID MapClickCommand(PSPAWNINFO pChar, PCHAR szLine)
{
if (!szLine[0])
{
SyntaxError("Usage: /mapclick <list|<key[+key[...]]> <clear|command>>");
return;
}
bRunNextCommand = TRUE;
CHAR szArg[MAX_STRING] = {0};
CHAR szBuffer[MAX_STRING] = {0};
GetArg(szArg,szLine,1);
PCHAR szRest = GetNextArg(szLine);
if (!stricmp(szArg,"list"))
{
int Count=0;
for (int i=1 ; i < 16 ; i++)
{
if (MapSpecialClickString[i][0])
{
sprintf(szBuffer,"%s: %s",DescribeCombo(i),MapSpecialClickString[i]);
WriteChatColor(szBuffer);
Count++;
}
}
sprintf(szBuffer,"%d special right-click commands",Count);
WriteChatColor(szBuffer);
return;
}
DWORD Combo=ParseCombo(szArg);
if (!Combo)
{
sprintf(szBuffer,"Invalid combo '%s'",szArg);
WriteChatColor(szBuffer);
return;
}
if (!szRest[0])
{
sprintf(szBuffer,"%s: %s",DescribeCombo(Combo),MapSpecialClickString[Combo]);
WriteChatColor(szBuffer);
return;
}
if (!stricmp(szRest,"clear"))
{
MapSpecialClickString[Combo][0]=0;
sprintf(szBuffer,"KeyCombo%d",Combo);
WritePrivateProfileString("Right Click",szBuffer,MapSpecialClickString[Combo],INIFileName);
sprintf(szBuffer,"%s cleared",DescribeCombo(Combo));
WriteChatColor(szBuffer);
return;
}
strcpy(MapSpecialClickString[Combo],szRest);
sprintf(szBuffer,"KeyCombo%d",Combo);
WritePrivateProfileString("Right Click",szBuffer,MapSpecialClickString[Combo],INIFileName);
sprintf(szBuffer,"%s: %s",DescribeCombo(Combo),MapSpecialClickString[Combo]);
WriteChatColor(szBuffer);
}
#endif
// marker code
PCHAR szMarkType[] = {
"None",
"Triangle",
"Square",
"Diamond",
"Ring",
};
PCHAR FormatMarker(PCHAR szLine,PCHAR szDest)
{
ZeroMemory(szDest,MAX_STRING);
CHAR MarkType[MAX_STRING] = {0};
CHAR MarkShape[MAX_STRING] = {0};
CHAR MarkSize[MAX_STRING] = {0};
GetArg(MarkType,szLine,1);
GetArg(MarkShape,szLine,2);
GetArg(MarkSize,szLine,3);
if (!strlen(MarkType)) {
sprintf(szDest,"unchanged, no spawn type given.");
return szDest;
}
if (!strlen(MarkShape)) {
sprintf(szDest,"unchanged, no shape given.");
return szDest;
}
for (DWORD i = 0; MapFilterOptions[i].szName != NULL; i++) {
if (!stricmp(MarkType, MapFilterOptions[i].szName)) {
DWORD Marker = FindMarker(MarkShape);
if (Marker == 99) {
sprintf(szDest,"unchanged, unknown shape: '%s'",MarkShape);
return szDest;
}
DWORD Size = 6;
if (strlen(MarkSize)) {
Size = (int)atoi(MarkSize);
if (!Size) {
sprintf(szDest,"unchanged, invalid size: '%s'",MarkSize);
return szDest;
}
}
CHAR tmp_1[MAX_STRING] = {0};
CHAR tmp_2[MAX_STRING] = {0};
sprintf(tmp_1,"%s-Size",MapFilterOptions[i].szName);
sprintf(tmp_2,"%d",Size);
WritePrivateProfileString("Marker Filters",MapFilterOptions[i].szName,szMarkType[Marker],INIFileName);
WritePrivateProfileString("Marker Filters",tmp_1,tmp_2,INIFileName);
MapFilterOptions[i].Marker = Marker;
MapFilterOptions[i].MarkerSize = Size;
sprintf(szDest,"'%s' is now set to '%s' with size %d.",MapFilterOptions[i].szName,szMarkType[Marker],Size);
return szDest;
}
}
sprintf(szDest,"unchanged, unknown spawn type: %s",MarkType);
return szDest;
}