vanilla-wow-addons – Rev 1
?pathlinks?
gGroupCalendar_Database =
{
Format = 11,
Databases = {},
};
gGroupCalendar_UserDatabase = nil;
gGroupCalendar_MaximumEventAge = 30;
gGroupCalendar_MinimumEventDate = nil;
gGroupCalendar_PlayerCharacters = {};
gGroupCalendar_40ManLimits =
{
mClassLimits =
{
P = {mMin = 4, mMax = 6},
R = {mMin = 4, mMax = 6},
D = {mMin = 4, mMax = 6},
W = {mMin = 4, mMax = 6},
H = {mMin = 4, mMax = 6},
K = {mMin = 4, mMax = 6},
M = {mMin = 4, mMax = 6},
L = {mMin = 4, mMax = 6},
S = {mMin = 4, mMax = 6},
},
mMaxAttendance = 40,
};
gGroupCalendar_20ManLimits =
{
mClassLimits =
{
P = {mMin = 2, mMax = 3},
R = {mMin = 2, mMax = 3},
D = {mMin = 2, mMax = 3},
W = {mMin = 2, mMax = 3},
H = {mMin = 2, mMax = 3},
K = {mMin = 2, mMax = 3},
M = {mMin = 2, mMax = 3},
L = {mMin = 2, mMax = 3},
S = {mMin = 2, mMax = 3},
},
mMaxAttendance = 20,
};
gGroupCalendar_15ManLimits =
{
mClassLimits =
{
P = {mMin = 1, mMax = 3},
R = {mMin = 1, mMax = 3},
D = {mMin = 1, mMax = 3},
W = {mMin = 1, mMax = 3},
H = {mMin = 1, mMax = 3},
K = {mMin = 1, mMax = 3},
M = {mMin = 1, mMax = 3},
L = {mMin = 1, mMax = 3},
S = {mMin = 1, mMax = 3},
},
mMaxAttendance = 15,
};
gGroupCalendar_10ManLimits =
{
mClassLimits =
{
P = {mMin = 1, mMax = 2},
R = {mMin = 1, mMax = 2},
D = {mMin = 1, mMax = 2},
W = {mMin = 1, mMax = 2},
H = {mMin = 1, mMax = 2},
K = {mMin = 1, mMax = 2},
M = {mMin = 1, mMax = 2},
L = {mMin = 1, mMax = 2},
S = {mMin = 1, mMax = 2},
},
mMaxAttendance = 10,
};
gGroupCalendar_5ManLimits =
{
mClassLimits =
{
P = {mMax = 1},
R = {mMax = 1},
D = {mMax = 1},
W = {mMax = 1},
H = {mMax = 1},
K = {mMax = 1},
M = {mMax = 1},
L = {mMax = 1},
S = {mMax = 1},
},
mMaxAttendance = 5,
};
gGroupCalendar_EventTypes =
{
General =
{
Title = GroupCalendar_cGeneralEventGroup,
MenuHint = "FLAT",
Events =
{
{id="Meet", name=GroupCalendar_cMeetingEventName},
{id="Birth", name=GroupCalendar_cBirthdayEventName},
},
},
Dungeon =
{
Title = GroupCalendar_cDungeonEventGroup,
MenuHint = "FLAT",
Events =
{
{id="AQT", name = GroupCalendar_cAQTEventName, limits = gGroupCalendar_40ManLimits},
{id="AQR", name = GroupCalendar_cAQREventName, limits = gGroupCalendar_20ManLimits},
{id="BWL", name = GroupCalendar_cBWLEventName, limits = gGroupCalendar_40ManLimits},
{id="MC", name = GroupCalendar_cMCEventName, limits = gGroupCalendar_40ManLimits},
{id="Onyxia", name = GroupCalendar_cOnyxiaEventName, limits = gGroupCalendar_40ManLimits},
{id="ZG", name = GroupCalendar_cZGEventName, limits = gGroupCalendar_20ManLimits},
{id="UBRS", name = GroupCalendar_cUBRSEventName, limits = gGroupCalendar_15ManLimits},
{id="Scholo", name = GroupCalendar_cScholoEventName, limits = gGroupCalendar_5ManLimits},
{id="DM", name = GroupCalendar_cDMEventName, limits = gGroupCalendar_5ManLimits},
{id="Strath", name = GroupCalendar_cStrathEventName, limits = gGroupCalendar_5ManLimits},
{id="LBRS", name = GroupCalendar_cLBRSEventName, limits = gGroupCalendar_5ManLimits},
{id="BRD", name = GroupCalendar_cBRDEventName, limits = gGroupCalendar_5ManLimits},
{id="ST", name = GroupCalendar_cSTEventName, limits = gGroupCalendar_5ManLimits},
{id="ZF", name = GroupCalendar_cZFEventName, limits = gGroupCalendar_5ManLimits},
{id="Mara", name = GroupCalendar_cMaraEventName, limits = gGroupCalendar_5ManLimits},
{id="Uld", name = GroupCalendar_cUldEventName, limits = gGroupCalendar_5ManLimits},
{id="RFD", name = GroupCalendar_cRFDEventName, limits = gGroupCalendar_5ManLimits},
{id="SM", name = GroupCalendar_cSMEventName, limits = gGroupCalendar_5ManLimits},
{id="RFK", name = GroupCalendar_cRFKEventName, limits = gGroupCalendar_5ManLimits},
{id="Gnomer", name = GroupCalendar_cGnomerEventName, limits = gGroupCalendar_5ManLimits},
{id="BFD", name = GroupCalendar_cBFDEventName, limits = gGroupCalendar_5ManLimits},
{id="Stockades", name = GroupCalendar_cStockadesEventName, limits = gGroupCalendar_5ManLimits},
{id="SFK", name = GroupCalendar_cSFKEventName, limits = gGroupCalendar_5ManLimits},
{id="WC", name = GroupCalendar_cWCEventName, limits = gGroupCalendar_5ManLimits},
{id="Deadmines", name = GroupCalendar_cDeadminesEventName, limits = gGroupCalendar_5ManLimits},
{id="RFC", name = GroupCalendar_cRFCEventName, limits = gGroupCalendar_5ManLimits},
},
},
Battleground =
{
Title = GroupCalendar_cBattlegroundEventGroup,
MenuHint = "HIER",
Events =
{
{id="AV", name=GroupCalendar_cAVEventName},
{id="AB", name=GroupCalendar_cABEventName},
{id="WSG", name=GroupCalendar_cWSGEventName},
},
},
Reset =
{
Title = nil,
Events =
{
{id="RSOny", name=GroupCalendar_cOnyxiaResetEventName}, -- Onyxia reset
{id="RSMC", name=GroupCalendar_cMCResetEventName}, -- MC reset
{id="RSBWL", name=GroupCalendar_cBWLResetEventName}, -- BWL reset
{id="RSZG", name=GroupCalendar_cZGResetEventName}, -- ZG reset
{id="RSAQT", name=GroupCalendar_cAQTResetEventName}, -- AQT reset
{id="RSAQR", name=GroupCalendar_cAQRResetEventName}, -- AQR reset
{id="RSXmut", name=GroupCalendar_cTransmuteCooldownEventName}, -- Transmute
{id="RSSalt", name=GroupCalendar_cSaltShakerCooldownEventName}, -- Salt shaker
{id="RSMoon", name=GroupCalendar_cMoonclothCooldownEventName}, -- Mooncloth
{id="RSSnow", name=GroupCalendar_cSnowmasterCooldownEventName}, -- Snowmaster 9000
},
ResetEventInfo =
{
RSZG = {left = 0.0, top = 0.25, right = 0.25, bottom = 0.5, isDungeon = true, name=GroupCalendar_cRaidInfoZGName, largeIcon="ZG"},
RSOny = {left = 0.25, top = 0.25, right = 0.5, bottom = 0.5, isDungeon = true, name=GroupCalendar_cRaidInfoOnyxiaName, largeIcon="Onyxia"},
RSMC = {left = 0.5, top = 0.25, right = 0.75, bottom = 0.5, isDungeon = true, name=GroupCalendar_cRaidInfoMCName, largeIcon="MC"},
RSBWL = {left = 0.75, top = 0.25, right = 1.0, bottom = 0.5, isDungeon = true, name=GroupCalendar_cRaidInfoBWLName, largeIcon="BWL"},
RSAQT = {left = 0.0, top = 0.5, right = 0.25, bottom = 1.0, isDungeon = true, name=GroupCalendar_cRaidInfoAQTName, largeIcon="AQT"},
RSAQR = {left = 0.25, top = 0.5, right = 0.5, bottom = 1.0, isDungeon = true, name=GroupCalendar_cRaidInfoAQRName, largeIcon="AQR"},
RSXmut = {left = 0.50, top = 0, right = 0.75, bottom = 0.25, isTradeskill = true, id="Alchemy", largeSysIcon="Interface\\Icons\\Trade_Alchemy"},
RSSalt = {left = 0.25, top = 0, right = 0.5, bottom = 0.25, isTradeskill = true, id="Leatherworking", largeSysIcon="Interface\\Icons\\Trade_Leatherworking"},
RSMoon = {left = 0, top = 0, right = 0.25, bottom = 0.25, isTradeskill = true, id="Tailoring", largeSysIcon="Interface\\Icons\\Trade_Tailoring"},
RSSnow = {left = 0.75, top = 0, right = 1.0, bottom = 0.25, isTradeskill = true, id="Snowmaster", largeSysIcon="Interface\\Icons\\Spell_Frost_WindWalkOn"},
},
},
};
gGroupCalendar_ClassInfoByClassCode =
{
D = {name = GroupCalendar_cDruidClassName, color = GroupCalendar_cDruidClassColorName, element = "Druid"},
H = {name = GroupCalendar_cHunterClassName, color = GroupCalendar_cHunterClassColorName, element = "Hunter"},
M = {name = GroupCalendar_cMageClassName, color = GroupCalendar_cMageClassColorName, element = "Mage"},
L = {name = GroupCalendar_cPaladinClassName, color = GroupCalendar_cPaladinClassColorName, element = "Paladin", faction="Alliance"},
P = {name = GroupCalendar_cPriestClassName, color = GroupCalendar_cPriestClassColorName, element = "Priest"},
R = {name = GroupCalendar_cRogueClassName, color = GroupCalendar_cRogueClassColorName, element = "Rogue"},
S = {name = GroupCalendar_cShamanClassName, color = GroupCalendar_cShamanClassColorName, element = "Shaman", faction="Horde"},
K = {name = GroupCalendar_cWarlockClassName, color = GroupCalendar_cWarlockClassColorName, element = "Warlock"},
W = {name = GroupCalendar_cWarriorClassName, color = GroupCalendar_cWarriorClassColorName, element = "Warrior"},
};
gGroupCalendar_RaceNamesByRaceCode =
{
A = {name = GroupCalendar_cDraeneiRaceName, faction="Alliance"},
D = {name = GroupCalendar_cDwarfRaceName, faction="Alliance"},
G = {name = GroupCalendar_cGnomeRaceName, faction="Alliance"},
H = {name = GroupCalendar_cHumanRaceName, faction="Alliance"},
N = {name = GroupCalendar_cNightElfRaceName, faction="Alliance"},
B = {name = GroupCalendar_cBloodElfRaceName, faction="Horde"},
O = {name = GroupCalendar_cOrcRaceName, faction="Horde"},
T = {name = GroupCalendar_cTaurenRaceName, faction="Horde"},
R = {name = GroupCalendar_cTrollRaceName, faction="Horde"},
U = {name = GroupCalendar_cUndeadRaceName, faction="Horde"},
};
function EventDatabase_DatabaseIsVisible(pDatabase)
return pDatabase
and pDatabase.Realm == gGroupCalendar_RealmName
and (pDatabase.IsPlayerOwned
or (pDatabase.LocalUsers
and pDatabase.LocalUsers[gGroupCalendar_PlayerName]));
end
function EventDatabase_GetDatabase(pUserName, pCreate)
if not pUserName then
Calendar_DebugMessage("EventDatabase_GetDatabase: pUserName is nil");
return;
end
local vDatabase = gGroupCalendar_Database.Databases[gGroupCalendar_RealmName.."_"..pUserName];
if not vDatabase then
if pCreate then
vDatabase = {};
vDatabase.UserName = pUserName;
vDatabase.IsPlayerOwned = pUserName == gGroupCalendar_PlayerName;
vDatabase.CurrentEventID = 0;
vDatabase.Realm = gGroupCalendar_RealmName;
vDatabase.Events = {};
vDatabase.Changes = nil;
vDatabase.RSVPs = nil;
vDatabase.LocalUsers = {};
vDatabase.Guild = gGroupCalendar_PlayerGuild;
gGroupCalendar_Database.Databases[gGroupCalendar_RealmName.."_"..pUserName] = vDatabase;
if vDatabase.IsPlayerOwned then
gGroupCalendar_PlayerCharacters[gGroupCalendar_PlayerName] = true;
end
else
return nil;
end
end
if not vDatabase.IsPlayerOwned
and (not vDatabase.LocalUsers
or not vDatabase.LocalUsers[gGroupCalendar_PlayerName]) then
if not pCreate then
return nil;
end
if not vDatabase.LocalUsers then
vDatabase.LocalUsers = {};
end
vDatabase.LocalUsers[gGroupCalendar_PlayerName] = true;
end
if vDatabase
and not vDatabase.IsPlayerOwned
and pUserName == gGroupCalendar_PlayerName then
vDatabase.IsPlayerOwned = true;
end
return vDatabase;
end
function EventDatabase_GetOwnedDatabases()
local vOwnedDatabases = {};
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if EventDatabase_DatabaseIsVisible(vDatabase)
and vDatabase.IsPlayerOwned
and vDatabase.PlayerLevel then -- Skip databases which haven't been visited since this version
table.insert(vOwnedDatabases, vDatabase);
end
end
return vOwnedDatabases;
end
function EventDatabase_AssumeDatabase(pUserName)
local vDatabase = gGroupCalendar_Database.Databases[gGroupCalendar_RealmName.."_"..pUserName];
if not vDatabase then
return nil;
end
if not vDatabase.IsPlayerOwned
and not vDatabase.LocalUsers[gGroupCalendar_PlayerName] then
vDatabase.LocalUsers[gGroupCalendar_PlayerName] = true;
GroupCalendar_MajorDatabaseChange(vDatabase);
end
return vDatabase;
end
function EventDatabase_DeleteDatabase(pUserName)
local vDatabase = gGroupCalendar_Database.Databases[gGroupCalendar_RealmName.."_"..pUserName];
if not vDatabase then
return;
end
if vDatabase.LocalUsers then
vDatabase.LocalUsers[gGroupCalendar_PlayerName] = nil;
end
if Calendar_ArrayIsEmpty(vDatabase.LocalUsers) then
gGroupCalendar_Database.Databases[gGroupCalendar_RealmName.."_"..pUserName] = nil;
end
GroupCalendar_MajorDatabaseChange(vDatabase);
end
function EventDatabase_GetChanges(pDatabase)
local vChanges = pDatabase.Changes;
if not vChanges then
vChanges = CalendarChanges_New();
pDatabase.Changes = vChanges;
end
return vChanges;
end
function EventDatabase_SetUserName(pUserName)
gGroupCalendar_UserDatabase = EventDatabase_GetDatabase(gGroupCalendar_PlayerName, true);
gGroupCalendar_UserDatabase.PlayerRaceCode = EventDatabase_GetRaceCodeByRace(UnitRace("PLAYER"));
gGroupCalendar_UserDatabase.PlayerClassCode = EventDatabase_GetClassCodeByClass(UnitClass("PLAYER"));
end
function EventDatabase_NewEvent(pDatabase, pDate)
local vEvent = {};
vEvent.mType = nil;
vEvent.mTitle = nil;
vEvent.mTime = 1140;
vEvent.mDate = pDate;
vEvent.mDuration = 120;
vEvent.mDescription = nil;
vEvent.mMinLevel = 0;
vEvent.mAttendance = nil;
vEvent.mPrivate = nil;
vEvent.mManualConfirm = false;
vEvent.mLimits = nil;
pDatabase.CurrentEventID = pDatabase.CurrentEventID + 1;
vEvent.mID = pDatabase.CurrentEventID;
return vEvent;
end
function EventDatabase_AddEvent(pDatabase, pEvent, pSilent)
local vSchedule = pDatabase.Events[pEvent.mDate];
if vSchedule == nil then
vSchedule = {};
pDatabase.Events[pEvent.mDate] = vSchedule;
end
-- append the event
table.insert(vSchedule, pEvent);
if not pSilent then
EventDatabase_EventAdded(pDatabase, pEvent);
end
end
function EventDatabase_GetDateSchedule(pDate)
return gGroupCalendar_UserDatabase.Events[pDate];
end
function EventDatabase_GetCompiledSchedule(pDate)
local vCompiledSchedule = {};
if gGroupCalendar_Settings.ShowEventsInLocalTime then
local vDate2 = nil;
if gGroupCalendar_ServerTimeZoneOffset < 0 then
vDate2 = pDate + 1;
elseif gGroupCalendar_ServerTimeZoneOffset > 0 then
vDate2 = pDate - 1;
end
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if EventDatabase_DatabaseIsVisible(vDatabase) then
for vDateIndex = 1, 2 do
local vDate;
if vDateIndex == 1 then
vDate = pDate;
else
if not vDate2 then
break;
end
vDate = vDate2;
end
local vSchedule = vDatabase.Events[vDate];
if vSchedule then
for vIndex, vEvent in vSchedule do
-- Calculate the local date/time and see if it's still the right date
local vLocalDate, vLocalTime = Calendar_GetLocalDateTimeFromServerDateTime(vDate, vEvent.mTime);
if vLocalDate == pDate then
local vCompiledEvent = {mOwner = vDatabase.UserName, mEvent = vEvent};
table.insert(vCompiledSchedule, vCompiledEvent);
end
end
end
end
end
end
else
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if EventDatabase_DatabaseIsVisible(vDatabase) then
local vSchedule = vDatabase.Events[pDate];
if vSchedule then
for vIndex, vEvent in vSchedule do
local vCompiledEvent = {mOwner = vDatabase.UserName, mEvent = vEvent};
table.insert(vCompiledSchedule, vCompiledEvent);
end
end
end
end
end
table.sort(vCompiledSchedule, EventDatabase_CompareCompiledEvents);
return vCompiledSchedule;
end
function EventDatabase_CompareCompiledEvents(pCompiledEvent1, pCompiledEvent2)
return EventDatabase_CompareEvents(pCompiledEvent1.mEvent, pCompiledEvent2.mEvent);
end
function EventDatabase_GetEventDisplayName(pEvent)
if pEvent.mTitle and pEvent.mTitle ~= "" then
return Calendar_UnescapeString(pEvent.mTitle);
else
local vName = EventDatabase_GetEventNameByID(pEvent.mType);
if vName ~= nil then
return vName;
else
return "";
end
end
end
function EventDatabase_CompareEvents(pEvent1, pEvent2)
-- If either event has nil for a time (all day event) then
-- sort based on time or display name
if not pEvent1.mTime or not pEvent2.mTime then
if pEvent1.mTime == pEvent2.mTime then
return EventDatabase_GetEventDisplayName(pEvent1) < EventDatabase_GetEventDisplayName(pEvent2);
elseif pEvent1.mTime == nil then
return true;
else
return false;
end
-- Otherwise compare dates first
elseif pEvent1.mDate < pEvent2.mDate then
return true;
elseif pEvent1.mDate > pEvent2.mDate then
return false;
-- Dates are the same, compare times
elseif pEvent1.mTime == pEvent2.mTime then
return EventDatabase_GetEventDisplayName(pEvent1) < EventDatabase_GetEventDisplayName(pEvent2);
else
return pEvent1.mTime < pEvent2.mTime;
end
end
function EventDatabase_GetEventIndex(pSchedule, pEvent)
for vIndex, vEvent in pSchedule do
if vEvent == pEvent then
return vIndex;
end
end
return 0;
end
function EventDatabase_ScheduleIsEmpty(pSchedule)
for vIndex, vEvent in pSchedule do
return false;
end
return true;
end
function EventDatabase_FindEventByID(pDatabase, pEventID)
for vDate, vSchedule in pDatabase.Events do
for vEventIndex, vEvent in vSchedule do
if vEvent.mID == pEventID then
return vEvent, vDate;
end
end
end
return nil;
end
function EventDatabase_DeleteEvent(pDatabase, pEvent, pSilent)
return EventDatabase_DeleteEventFromDate(pDatabase, pEvent.mDate, pEvent, pSilent);
end
function EventDatabase_DeleteEventFromDate(pDatabase, pDate, pEvent, pSilent)
-- Get the event's schedule
local vSchedule = pDatabase.Events[pDate];
if vSchedule == nil then
return false;
end
-- Find the event index
local vEventIndex = EventDatabase_GetEventIndex(vSchedule, pEvent);
if vEventIndex == 0 then
return false;
end
-- Notify that the event is being removed
if not pSilent
and pDatabase.IsPlayerOwned then
CalendarNetwork_RemovingEvent(pDatabase, pEvent);
end
-- Remove any pending RSVPs for the event
EventDatabase_RemoveAllRSVPsForEvent(pDatabase, pEvent, false);
-- Remove the event
table.remove(vSchedule, vEventIndex);
if EventDatabase_ScheduleIsEmpty(vSchedule) then
pDatabase.Events[pDate] = nil;
vSchedule = nil;
end
-- Notify that the schedule changed
GroupCalendar_ScheduleChanged(pDatabase, pDate);
return true;
end
function EventDatabase_GetEventInfoByID(pID)
for vGroupID, vEventGroup in gGroupCalendar_EventTypes do
for vIndex, vEventInfo in vEventGroup.Events do
if vEventInfo.id == pID then
return vEventInfo;
end
end
end
return nil;
end
function EventDatabase_GetEventNameByID(pID)
local vEventInfo = EventDatabase_GetEventInfoByID(pID);
if not vEventInfo then
return nil;
end
return vEventInfo.name;
end
function EventDatabase_GetStandardLimitsByID(pID)
local vEventInfo = EventDatabase_GetEventInfoByID(pID);
if not vEventInfo
or not vEventInfo.limits then
return nil;
end
-- Remove limit for classes from the "wrong" faction
for vClassCode, vClassLimit in vEventInfo.limits.mClassLimits do
local vClassInfo = gGroupCalendar_ClassInfoByClassCode[vClassCode];
if vClassInfo.faction
and vClassInfo.faction ~= gGroupCalendar_PlayerFactionGroup then
vEventInfo.limits.mClassLimits[vClassCode] = nil;
end
end
--
return vEventInfo.limits;
end
function EventDatabase_EventAdded(pDatabase, pEvent)
-- Notify the calendar
GroupCalendar_ScheduleChanged(pDatabase, pEvent.mDate);
-- Notify the network
CalendarNetwork_NewEvent(pDatabase, pEvent);
end
function EventDatabase_EventChanged(pDatabase, pEvent, pChangedFields)
-- If the date changed then move the event to the appropriate slot
if pChangedFields and pChangedFields.mDate then
local vEvent, vDate = EventDatabase_FindEventByID(pDatabase, pEvent.mID);
if vDate ~= pEvent.mDate then
EventDatabase_DeleteEventFromDate(pDatabase, vDate, pEvent, true);
EventDatabase_AddEvent(pDatabase, pEvent, true);
end
end
-- Update pending RSVPs based on event contents
if pChangedFields and pChangedFields.mAttendance then
if pChangedFields.mAttendance.op == "UPD" then
for vAttendeeName, vRSVPString in pChangedFields.mAttendance.val do
local vDatabase = EventDatabase_GetDatabase(vAttendeeName, false);
if vDatabase then
-- Remove any older (or same) RSVP for this person
local vRSVP = EventDatabase_UnpackEventRSVP(pDatabase.UserName, vAttendeeName, pEvent.mID, vRSVPString);
EventDatabase_RemoveOlderRSVP(vDatabase, vRSVP)
end
end
else
Calendar_DumpArray("EventDatabase_EventChanged: ", pChangedFields);
Calendar_DebugMessage("EventDatabase_EventChanged: Attendance op "..pChangedFields.mAttendance.op.." not recognized");
end
end
-- Notify the calendar
GroupCalendar_EventChanged(pDatabase, pEvent, pChangedFields);
-- Notify the network
CalendarNetwork_EventChanged(pDatabase, pEvent, pChangedFields);
end
function EventDatabase_GetCurrentChangeList(pDatabase)
local vChanges = EventDatabase_GetChanges(pDatabase);
local vChangeList, vRevisionChanged = CalendarChanges_GetCurrentChangeList(vChanges);
if vRevisionChanged and pDatabase.IsPlayerOwned then
CalendarNetwork_DBRevisionChanged(pDatabase);
end
return vChangeList;
end
function EventDatabase_GetDBRevisionPath(pUserName, pDatabaseID, pRevision, pAuthRevision)
return CalendarChanges_GetRevisionPath("DB", pUserName, pDatabaseID, pRevision, pAuthRevision);
end
function EventDatabase_GetRSVPRevisionPath(pUserName, pDatabaseID, pRevision, pAuthRevision)
return CalendarChanges_GetRevisionPath("RAT", pUserName, pDatabaseID, pRevision, pAuthRevision);
end
function EventDatabase_GetEventPath(pEvent)
return "EVT:"..pEvent.mID.."/";
end
function EventDatabase_GenerateEventChangeString(pOpcode, pEvent, pEventPath)
local vChange;
-- Basic fields: type, date, time, duration, minLevel, maxLevel
vChange = pEventPath..pOpcode..":";
if pEvent.mType ~= nil then
vChange = vChange..pEvent.mType..",";
else
vChange = vChange..",";
end
if pEvent.mDate ~= nil then
vChange = vChange..pEvent.mDate..",";
else
vChange = vChange..",";
end
if pEvent.mTime ~= nil then
vChange = vChange..pEvent.mTime..",";
else
vChange = vChange..",";
end
if pEvent.mDuration ~= nil then
vChange = vChange..pEvent.mDuration..",";
else
vChange = vChange..",";
end
if pEvent.mMinLevel ~= nil then
vChange = vChange..pEvent.mMinLevel..",";
else
vChange = vChange..",";
end
if pEvent.mMaxLevel ~= nil then
vChange = vChange..pEvent.mMaxLevel;
end
return vChange;
end
function EventDatabase_AppendNewEvent(pChangeList, pEvent, pEventPath)
-- Basic fields: type, date, time, duration, minLevel, maxLevel
table.insert(pChangeList, EventDatabase_GenerateEventChangeString("NEW", pEvent, pEventPath));
-- Title
if pEvent.mTitle then
table.insert(pChangeList, pEventPath.."TIT:"..pEvent.mTitle);
end
if pEvent.mDescription ~= nil then
table.insert(pChangeList, pEventPath.."DSC:"..pEvent.mDescription);
end
if pEvent.mManualConfirm then
table.insert(pChangeList, pEventPath.."CNF:MAN");
elseif pEvent.mLimits then
local vConfConfigString = "CNF:AUT";
if pEvent.mLimits.mMaxAttendance then
vConfConfigString = vConfConfigString.."/MAX:"..pEvent.mLimits.mMaxAttendance;
end
if pEvent.mLimits.mClassLimits then
for vClassCode, vClassLimit in pEvent.mLimits.mClassLimits do
vConfConfigString = vConfConfigString.."/"..vClassCode..":";
if vClassLimit.mMin then
vConfConfigString = vConfConfigString..vClassLimit.mMin;
end
if vClassLimit.mMax then
vConfConfigString = vConfConfigString..","..vClassLimit.mMax;
end
end
end
table.insert(pChangeList, pEventPath..vConfConfigString);
end
-- Add attendance info
if pEvent.mAttendance then
for vAttendeeName, vAttendance in pEvent.mAttendance do
table.insert(pChangeList, pEventPath.."ATT:"..vAttendeeName..","..vAttendance);
end
end
table.insert(pChangeList, pEventPath.."END");
end
function EventDatabase_AppendEventUpdate(pChangeList, pEvent, pEventPath, pChangedFields)
local vNeedUpdateWrapper = false;
-- See if fields sent in the NEW or UPD wrapper are being changed. If so, the
-- wrapper needs to be sent, otherwise it can be omitted to save bandwidth
if pChangedFields.mType
or pChangedFields.mDate
or pChangedFields.mTime
or pChangedFields.mDuration
or pChangedFields.mMinLevel
or pChangedFields.mMaxLevel then
vNeedUpdateWrapper = true;
end
-- Basic fields: type, date, time, duration, minLevel, maxLevel
if vNeedUpdateWrapper then
table.insert(pChangeList, EventDatabase_GenerateEventChangeString("UPD", pEvent, pEventPath));
end
-- Title
if pChangedFields.mTitle ~= nil then
if pEvent.mTitle then
table.insert(pChangeList, pEventPath.."TIT:"..pEvent.mTitle);
end
end
if pChangedFields.mDescription ~= nil then
if pEvent.mDescription ~= nil then
table.insert(pChangeList, pEventPath.."DSC:"..pEvent.mDescription);
end
end
if pChangedFields.mManualConfirm ~= nil
or pChangedFields.mLimits ~= nil then
if pEvent.mManualConfirm then
table.insert(pChangeList, pEventPath.."CNF:MAN");
elseif pEvent.mLimits then
local vConfConfigString = "CNF:AUT";
if pEvent.mLimits.mMaxAttendance then
vConfConfigString = vConfConfigString.."/MAX:"..pEvent.mLimits.mMaxAttendance;
end
if pEvent.mLimits.mClassLimits then
for vClassCode, vClassLimit in pEvent.mLimits.mClassLimits do
vConfConfigString = vConfConfigString.."/"..vClassCode..":";
if vClassLimit.mMin then
vConfConfigString = vConfConfigString..vClassLimit.mMin;
end
if vClassLimit.mMax then
vConfConfigString = vConfConfigString..","..vClassLimit.mMax;
end
end
end
table.insert(pChangeList, pEventPath..vConfConfigString);
end
end
if pChangedFields.mAttendance ~= nil then
if pChangedFields.mAttendance.op == "UPD" then
for vAttendeeName, vEventRSVPString in pChangedFields.mAttendance.val do
local vAttendeeRSVPString = pEvent.mAttendance[vAttendeeName];
local vAttendeePath = pEventPath.."ATT:"..vAttendeeName;
if not vAttendeeRSVPString then
table.insert(pChangeList, vAttendeePath);
else
table.insert(pChangeList, vAttendeePath..","..vAttendeeRSVPString);
end
end
else
Calendar_DebugMessage("EventDatabase_AppendEventUpdate: Unknown attendance opcode "..pChangedFields.mAttendance.op);
end
end
if vNeedUpdateWrapper then
table.insert(pChangeList, pEventPath.."END");
end
end
function EventDatabase_RemoveEventChanges(pDatabase, pEvent)
-- Nothing to do if there are no changes
if not pDatabase.Changes then
return;
end
-- Remove all prior occurances for this event
for vRevision, vChangeList in pDatabase.Changes.ChangeList do
local vEventPath = EventDatabase_GetEventPath(pEvent);
local vPathLength = string.len(vEventPath);
local vNumChanges = table.getn(vChangeList);
local vChangeIndex = 1;
while vChangeIndex <= vNumChanges do
vChange = vChangeList[vChangeIndex];
if vChange ~= nil
and string.sub(vChange, 1, vPathLength) == vEventPath then
table.remove(vChangeList, vIndex);
vNumChanges = vNumChanges - 1;
else
vChangeIndex = vChangeIndex + 1;
end
end
if vNumChanges == 0 then
pDatabase.Changes.ChangeList[vRevision] = nil;
end
end
end
function EventDatabase_RebuildPlayerDatabases()
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.IsPlayerOwned
and vDatabase.Realm == gGroupCalendar_RealmName then
EventDatabase_RebuildDatabase(vDatabase);
end
end -- for vRealmUser, vDatabase
end
----------------------------------------
-- EventDatabase_CalculateHighestUsedEventID
-- Calculates the highest event ID in use by the database
----------------------------------------
function EventDatabase_CalculateHighestUsedEventID(pDatabase)
local vHighestID = nil;
for vDate, vSchedule in pDatabase.Events do
for vEventIndex, vEvent in vSchedule do
if not vHighestID
or vHighestID < vEvent.mID then
vHighestID = vEvent.mID;
end
end -- for vEventIndex, vEvent
end -- for vDate, vSchedule
end
----------------------------------------
-- EventDatabase_RepairEventIDs
-- Scans the database an ensures that every event has
-- a unique ID
----------------------------------------
function EventDatabase_RepairEventIDs(pDatabase)
local vCurrentID = EventDatabase_CalculateHighestUsedEventID(pDatabase);
-- Just return if there are no events
if not vCurrentID then
return;
end
-- Adjust the highest ID if it is lower than current ID
if vCurrentID < pDatabase.CurrentEventID then
vCurrentID = pDatabase.CurrentEventID;
end
-- Start making a map of used event IDs and
-- use up the next ID if a collision is detected
local vUsedIDs = {};
for vDate, vSchedule in pDatabase.Events do
for vEventIndex, vEvent in vSchedule do
if not vUsedIDs[vEvent.mID] then
vUsedIDs[vEvent.mID] = true;
else
-- Collision
vCurrentID = vCurrentID + 1;
vEvent.mID = vCurrentID;
end
end -- for vEventIndex, vEvent
end -- for vDate, vSchedule
-- Save the new current ID
pDatabase.CurrentEventID = vCurrentID;
end
----------------------------------------
-- EventDatabase_RebuildDatabase
-- Builds a new change history from the existing events
----------------------------------------
function EventDatabase_RebuildDatabase(pDatabase)
-- Repair event IDs
EventDatabase_RepairEventIDs(pDatabase);
-- Clear the revisions
pDatabase.Changes = nil;
-- Start a new revision
local vChangeList = nil;
-- Add each event to the revision
for vDate, vSchedule in pDatabase.Events do
for vEventIndex, vEvent in vSchedule do
if not vChangeList then
vChangeList = EventDatabase_GetCurrentChangeList(pDatabase);
end
local vEventPath = EventDatabase_GetEventPath(vEvent);
if not vEvent.mPrivate then
EventDatabase_AppendNewEvent(
vChangeList,
vEvent,
vEventPath);
end
end
end
if not vChangeList then
CalendarNetwork_SendEmptyChanges(pDatabase.Changes, "DB", pDatabase.UserName)
end
-- Compact the RSVP list and notify that they're updated
EventDatabase_RebuildRSVPs(pDatabase);
-- Notify the calendar that there was a major change
GroupCalendar_MajorDatabaseChange(pDatabase);
end
function EventDatabase_RebuildRSVPs(pDatabase)
if pDatabase.RSVPs then
CalendarChanges_Compact(pDatabase.RSVPs);
end
if not CalendarChanges_IsEmpty(pDatabase.RSVPs) then
CalendarNetwork_RSVPRevisionChanged(pDatabase);
else
CalendarNetwork_SendEmptyChanges(pDatabase.RSVPs, "RAT", pDatabase.UserName)
end
end
----------------------------------------
-- EventDatabase_ReconstructDatabase
-- Reconstructs the event records by re-playing the
-- change history
----------------------------------------
function EventDatabase_ReconstructDatabase(pDatabase)
-- Clear the events
pDatabase.Events = {};
-- Execute each change
if pDatabase.Changes then
for vRevision, vChangeList in pDatabase.Changes.ChangeList do
if gGroupCalendar_Settings.DebugReconstruct then
Calendar_DebugMessage("EventDatabase_ReconstructDatabase: Reconstruction revision "..vRevision.." in "..pDatabase.UserName);
end
EventDatabase_ExecuteChangeList(pDatabase, vChangeList, false);
end
end
GroupCalendar_MajorDatabaseChange(pDatabase);
end
function EventDatabase_ReprocessAllRSVPs(pDatabase)
local vRSVPs = pDatabase.RSVPs;
if not vRSVPs then
return;
end
for vRevision, vChangeList in vRSVPs.ChangeList do
EventDatabase_ExecuteRSVPChangeList(pDatabase, vChangeList, false);
end
end
function EventDatabase_ExecuteRSVPChangeList(pDatabase, pChangeList, pNotifyChanges)
pChangeList.IsOpen = nil; -- Make sure IsOpen is cleared, a bug may have caused it to remain open
local vIndex = 1;
local vNumChanges = table.getn(pChangeList);
while vIndex <= vNumChanges do
local vChange = pChangeList[vIndex];
if vChange then
local vCommands = CalendarNetwork_ParseCommandSubString("/"..vChange);
if not vCommands then
Calendar_DebugMessage("Invalid change entry found in RSVPs for "..pDatabase.UserName);
return;
end
local vOpcode = vCommands[1].opcode;
local vOperands = vCommands[1].operands;
table.remove(vCommands, 1);
if vOpcode == "EVT" then
local vRSVP = EventDatabase_UnpackRSVPFieldArray(vOperands, pDatabase.UserName);
if EventDatabase_ProcessRSVP(pDatabase, vRSVP) then
-- The request was consumed, remove it from the list
table.remove(pChangeList, vIndex);
vIndex = vIndex - 1;
vNumChanges = vNumChanges - 1;
end
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Unknown RSVP opcode "..vOpcode);
end
end
vIndex = vIndex + 1;
end
end
function EventDatabase_ExecuteChangeList(pDatabase, pChangeList, pNotifyChanges)
local vEvent = nil;
local vNewEvent = false;
local vQuickEvent = false;
local vEventDateChanged = false;
pChangeList.IsOpen = nil; -- Make sure IsOpen is cleared, a bug may have caused it to remain open
for vIndex, vChange in pChangeList do
local vCommands = CalendarNetwork_ParseCommandSubString("/"..vChange);
if not vCommands then
Calendar_DebugMessage("Invalid change entry found in database for "..pDatabase.UserName);
return;
end
local vOpcode = vCommands[1].opcode;
local vOperands = vCommands[1].operands;
table.remove(vCommands, 1);
if vOpcode == "EVT" then
local vEventID = tonumber(vOperands[1]);
local vEvtOpcode = vCommands[1].opcode;
local vEvtOperands = vCommands[1].operands;
table.remove(vCommands, 1);
if vEvtOpcode == "NEW" then
if vEvent and gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Starting new event while previous event is still open in database for "..pDatabase.UserName);
end
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("Adding event "..vEventID.." for "..pDatabase.UserName);
end
if not EventDatabase_FindEventByID(pDatabase, vEventID) then
local vDate = tonumber(vEvtOperands[2]);
if vDate >= gGroupCalendar_MinimumEventDate then
-- Create the event record
vEvent = {};
vNewEvent = true;
vEvent.mID = vEventID;
vEvent.mType = vEvtOperands[1];
vEvent.mDate = tonumber(vEvtOperands[2]);
vEvent.mTime = tonumber(vEvtOperands[3]);
vEvent.mDuration = tonumber(vEvtOperands[4]);
vEvent.mMinLevel = tonumber(vEvtOperands[5]);
vEvent.mMaxLevel = tonumber(vEvtOperands[6]);
EventDatabase_AddEvent(pDatabase, vEvent, true);
end
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event "..vEventID.." already exists in database for "..pDatabase.UserName);
end
elseif vEvtOpcode == "UPD" then
if vEvent and gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Updating event while previous event is still open in database for "..pDatabase.UserName);
end
vEvent = EventDatabase_FindEventByID(pDatabase, vEventID);
if vEvent then
local vDate = vEvent.mDate;
vEvent.mID = vEventID;
vEvent.mType = vEvtOperands[1];
vEvent.mDate = tonumber(vEvtOperands[2]);
vEvent.mTime = tonumber(vEvtOperands[3]);
vEvent.mDuration = tonumber(vEvtOperands[4]);
vEvent.mMinLevel = tonumber(vEvtOperands[5]);
vEvent.mMaxLevel = tonumber(vEvtOperands[6]);
vNewEvent = false;
vEventDateChanged = vEvent.mDate ~= vDate;
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event "..vEventID.." not found in database for "..pDatabase.UserName);
end
elseif vEvtOpcode == "TIT" then
if not vEvent then
vEvent = EventDatabase_FindEventByID(pDatabase, vEventID);
vQuickEvent = true;
end
if vEvent then
vEvent.mTitle = vEvtOperands[1];
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event "..vEventID.." not found in database for "..pDatabase.UserName);
end
elseif vEvtOpcode == "DSC" then
if not vEvent then
vEvent = EventDatabase_FindEventByID(pDatabase, vEventID);
vQuickEvent = true;
end
if vEvent then
vEvent.mDescription = vEvtOperands[1];
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event "..vEventID.." not found in database for "..pDatabase.UserName);
end
elseif vEvtOpcode == "ATT" then
if not vEvent then
vEvent = EventDatabase_FindEventByID(pDatabase, vEventID);
vQuickEvent = true;
end
if vEvent then
local vAttendeeName = vEvtOperands[1];
if not vEvent.mAttendance then
vEvent.mAttendance = {};
end
-- Add/update their attendance
local vNumOperands = table.getn(vEvtOperands);
local vAttendanceString = nil;
if vNumOperands > 1 then
for vOperandIndex = 2, vNumOperands do
local vOperand = vEvtOperands[vOperandIndex];
if vAttendanceString == nil then
vAttendanceString = "";
else
vAttendanceString = vAttendanceString..",";
end
if vOperand then
vAttendanceString = vAttendanceString..vOperand;
end
end
end
vEvent.mAttendance[vAttendeeName] = vAttendanceString;
-- Remove any older (or same) RSVP for this person
EventDatabase_RemoveOldAttendeeRSVP(vAttendeeName, pDatabase.UserName, vEventID, vAttendanceString);
-- Didn't find the specified event
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event "..vEventID.." not found in database for "..pDatabase.UserName);
end
elseif vEvtOpcode == "END" then
if vEvent then
if pNotifyChanges then
-- Notify the calendar
if vNewEvent then
GroupCalendar_ScheduleChanged(pDatabase, vEvent.mDate);
else
if vEventDateChanged then
local vEvent2, vDate = EventDatabase_FindEventByID(pDatabase, vEvent.mID);
if vDate ~= vEvent.mDate then
EventDatabase_DeleteEventFromDate(pDatabase, vDate, pEvent, true);
EventDatabase_AddEvent(pDatabase, vEvent, true);
end
end
GroupCalendar_EventChanged(pDatabase, vEvent, nil); -- only notify the calendar
end
end
vEvent = nil;
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Event not open when attemping to end update for "..pDatabase.UserName);
end
elseif vEvtOpcode == "DEL" then
vEvent = EventDatabase_FindEventByID(pDatabase, vEventID);
vQuickEvent = true;
if vEvent then
EventDatabase_DeleteEvent(pDatabase, vEvent, true);
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Can't delete event "..vEventID..": Event not found in database for "..pDatabase.UserName);
end
elseif gGroupCalendar_Settings.DebugErrors then
Calendar_DebugMessage("GroupCalendar: Unknown change operator "..vEvtOpcode);
end
if vQuickEvent then
vEvent = nil;
end
end
end
end
function EventDatabase_PurgeDatabase(pDatabase, pDatabaseID)
EventDatabase_RemoveAllRSVPsForDatabase(pDatabase, false)
pDatabase.CurrentEventID = 0;
pDatabase.Events = {};
pDatabase.Changes = CalendarChanges_New();
pDatabase.Changes.ID = pDatabaseID;
GroupCalendar_MajorDatabaseChange(pDatabase);
end
function EventDatabase_PurgeRSVPs(pDatabase, pDatabaseID)
pDatabase.RSVPs = CalendarChanges_New();
pDatabase.RSVPs.ID = pDatabaseID;
GroupCalendar_MajorDatabaseChange(pDatabase);
end
function EventDatabase_CheckDatabase(pDatabase)
-- Remove empty RSVP changelists
if pDatabase.RSVPs then
for vRevision, vChangeList in pDatabase.RSVPs.ChangeList do
if table.getn(vChangeList) == 0 then
pDatabase.RSVPs.ChangeList[vRevision] = nil;
end
end
end
-- Remove events with duplicate IDs
for vDate, vEvents in pDatabase.Events do
local vEventIndex = 1;
local vNumEvents = table.getn(vEvents);
while vEventIndex <= vNumEvents do
local vEvent = vEvents[vEventIndex];
if not vEvent
or EventDatabase_FindEventByID(pDatabase, vEvent.mID) ~= vEvent then
Calendar_DebugMessage("EventDatabase_CheckDatabase: Removing extra event ID "..vEvent.mID.." from database for "..pDatabase.UserName);
table.remove(vEvents, vEventIndex);
vNumEvents = vNumEvents - 1;
else
vEventIndex = vEventIndex + 1;
end
end
end
end
function EventDatabase_ScanForNewlines(pDatabase)
for vDate, vEvents in pDatabase.Events do
for vEventID, vEvent in vEvents do
if vEvent.mDescription then
vEvent.mDescription = string.gsub(vEvent.mDescription, "\n", "&n;");
end
end
end
if pDatabase.Changes and pDatabase.Changes.ChangeList then
for vRevision, vChanges in pDatabase.Changes.ChangeList do
for vIndex, vChange in vChanges do
if type(vIndex) == "number" then
vChanges[vIndex] = string.gsub(vChange, "\n", "&n;");
end
end
end
end
end
function EventDatabase_Initialize()
EventDatabase_CheckDatabases();
-- Update the list of player-owned databases
gGroupCalendar_PlayerCharacters = {};
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if EventDatabase_DatabaseIsVisible(vDatabase)
and vDatabase.IsPlayerOwned then
gGroupCalendar_PlayerCharacters[vDatabase.UserName] = true;
end
end
end
function EventDatabase_CheckDatabases()
-- Upgrade the database to format 4 (just purge all non-owned databases
-- and rebuild the owned ones)
if gGroupCalendar_Database.Format < 4 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.IsPlayerOwned then
EventDatabase_RebuildDatabase(vDatabase);
else
gGroupCalendar_Database.Databases[vRealmUser] = nil;
end
end
gGroupCalendar_Database.Format = 4;
end
-- Upgrade the database to format 5 (scan for newlines in event fields and escape them)
if gGroupCalendar_Database.Format < 5 then
for vRealmUser, vSettings in gGroupCalendar_Settings do
if type(vSettings) == "array" and vSettings.EventTemplates then
for vEventID, vEventTemplate in vSettings.EventTemplates do
if vEventTemplate.mDescription then
vEventTemplate.mDescription = string.gsub(vEventTemplate.mDescription, "\n", "&n;");
end
end
end
end
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
EventDatabase_ScanForNewlines(vDatabase);
end
gGroupCalendar_Database.Format = 5;
end
-- Upgrade the database to format 6 (just purge all non-owned databases
-- and rebuild the owned ones again)
if gGroupCalendar_Database.Format < 6 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.IsPlayerOwned then
EventDatabase_RebuildDatabase(vDatabase);
else
gGroupCalendar_Database.Databases[vRealmUser] = nil;
end
end
gGroupCalendar_Database.Format = 6;
end
-- Upgrade to format 7 (just purge all non-owned databases)
if gGroupCalendar_Database.Format < 7 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if not vDatabase.IsPlayerOwned then
gGroupCalendar_Database.Databases[vRealmUser] = nil;
end
end
gGroupCalendar_Database.Format = 7;
end
-- Upgrade to format 8 (rebuild all owned databases to force
-- them to the new version numbering system)
if gGroupCalendar_Database.Format < 8 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.IsPlayerOwned then
EventDatabase_RebuildDatabase(vDatabase);
end
end
gGroupCalendar_Database.Format = 8;
end
-- Upgrade to format 9 (reconstruct non-owned databases to correct
-- parsing errors)
if gGroupCalendar_Database.Format < 9 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if not vDatabase.IsPlayerOwned then
EventDatabase_ReconstructDatabase(vDatabase);
end
end
gGroupCalendar_Database.Format = 9;
end
-- Upgrade the database to format 10 (just purge all non-owned databases)
if gGroupCalendar_Database.Format < 10 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if not vDatabase.IsPlayerOwned then
gGroupCalendar_Database.Databases[vRealmUser] = nil;
end
end
gGroupCalendar_Database.Format = 10;
end
-- Upgrade the database to format 11 (ensure that RSVPs for deleted events have been removed
-- and that event IDs are numbers and not strings)
if gGroupCalendar_Database.Format < 11 then
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
-- Convert all event IDs to a number to fix a bug
-- caused by earlier versions
for vDate, vEvents in vDatabase.Events do
for vIndex, vEvent in vEvents do
vEvent.mID = tonumber(vEvent.mID);
end
end
end
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.IsPlayerOwned then
EventDatabase_RemoveObsoleteRSVPs(vDatabase);
EventDatabase_RebuildRSVPs(vDatabase);
else
EventDatabase_ReprocessAllRSVPs(vDatabase);
end
end
gGroupCalendar_Database.Format = 11;
end
-- Make sure the realm is set
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if not vDatabase.Realm then
local vStartIndex, vEndIndex, vRealmName = string.find(vRealmUser, "([^_]+)");
if vStartIndex ~= nil then
vDatabase.Realm = vRealmName;
end
end
EventDatabase_CheckDatabase(vDatabase);
end
-- Remove old events
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
EventDatabase_DeleteOldEvents(vDatabase);
end
end
function EventDatabase_CheckDatabaseTrust()
-- Return if they're in a guild but the roster isn't loaded
-- so that we don't go and delete a bunch of guildie calendars
-- by mistake
if IsInGuild() and GetNumGuildMembers() == 0 then
if gGroupCalendar_Settings.DebugInit then
Calendar_DebugMessage("CheckDatabaseTrust: Roster isn't loaded, scheduling a load");
end
CalendarNetwork_LoadGuildRoster();
return;
end
if gGroupCalendar_Settings.DebugInit then
Calendar_DebugMessage("CheckDatabaseTrust: Verifying trust");
end
-- Verify that each database is still trusted
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
-- Only check databases for the current realm
if EventDatabase_DatabaseIsVisible(vDatabase) then
-- See if they're still trusted
if not vDatabase.IsPlayerOwned
and not CalendarTrust_UserIsTrusted(vDatabase.UserName) then
-- not trusted anymore, remove their database
EventDatabase_DeleteDatabase(vDatabase.UserName);
end
end
end
end
function EventDatabase_GetDateTime60Stamp()
local vYear, vMonth, vDay, vHour, vMinute, vSecond = Calendar_GetCurrentYearMonthDayHourMinute();
local vDate = Calendar_ConvertMDYToDate(vMonth, vDay, vYear);
local vTime60 = Calendar_ConvertHMSToTime60(vHour, vMinute, vSecond);
return vDate, vTime60;
end
function EventDatabase_GetServerDateTime60Stamp()
local vYear, vMonth, vDay, vHour, vMinute, vSecond = Calendar_GetCurrentYearMonthDayHourMinute();
local vDate = Calendar_ConvertMDYToDate(vMonth, vDay, vYear);
local vTime = Calendar_ConvertHMToTime(vHour, vMinute);
vDate, vTime = Calendar_GetServerDateTimeFromLocalDateTime(vDate, vTime);
return vDate, vTime * 60 + vSecond;
end
function EventDatabase_GetRSVPs(pDatabase)
local vRSVPs = pDatabase.RSVPs;
if not vRSVPs then
vRSVPs = CalendarChanges_New();
pDatabase.RSVPs = vRSVPs;
end
return vRSVPs;
end
function EventDatabase_GetCurrentRSVPChangeList(pDatabase)
local vRSVPs = EventDatabase_GetRSVPs(pDatabase);
local vChangeList, vRevisionChanged = CalendarChanges_GetCurrentChangeList(vRSVPs);
if vRevisionChanged and pDatabase.IsPlayerOwned then
CalendarNetwork_RSVPRevisionChanged(pDatabase);
end
return vChangeList;
end
function EventDatabase_AddEventRSVP(pDatabase, pEvent, pAttendeeName, pRSVP)
-- Verify that the attendance request is newer than the existing one
local vExistingRSVP = EventDatabase_FindEventRSVP(pDatabase.UserName, pEvent, pAttendeeName);
if vExistingRSVP then
if vExistingRSVP.mDate > pRSVP.mDate
or (vExistingRSVP.mDate == pRSVP.mDate
and vExistingRSVP.mTime > pRSVP.mTime) then
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_AddEventRSVP: Ignore event attendance request for "..pAttendeeName.." for ".." event "..pRSVP.mEventID..": Request is out-of-date");
end
return;
end
end
-- Update the event attendance list
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_AddEventRSVP: Updating event attendance for "..pAttendeeName.." for ".." event "..pRSVP.mEventID);
end
if not pEvent.mAttendance then
pEvent.mAttendance = {};
end
local vEventRSVPString = EventDatabase_PackEventRSVP(pRSVP);
pEvent.mAttendance[pAttendeeName] = vEventRSVPString;
-- Notify the network of the change
local vChangedFields =
{
mAttendance =
{
op = "UPD",
val =
{
}
}
};
vChangedFields.mAttendance.val[pAttendeeName] = vEventRSVPString;
EventDatabase_EventChanged(pDatabase, pEvent, vChangedFields);
end
function EventDatabase_RemoveEventRSVP(pDatabase, pEvent, pAttendeeName)
if not pEvent.mAttendance then
return;
end
pEvent.mAttendance[pAttendeeName] = nil;
-- Notify the network of the change
local vChangedFields =
{
mAttendance =
{
op = "UPD",
val =
{
[pAttendeeName] = "-",
}
}
};
EventDatabase_EventChanged(pDatabase, pEvent, vChangedFields);
end
function EventDatabase_AddRSVPRequest(pDatabase, pRSVP)
-- Remove any existing RSVP for the same event
if not EventDatabase_RemoveOlderRSVP(pDatabase, pRSVP) then
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_AddRSVPRequest: Ignoring "..pDatabase.UserName..","..pRSVP.mEventID..": "..pRSVP.mStatus);
end
return; -- A newer request already exists so disregard this one
end
-- Add the new RSVP
local vChangeList = EventDatabase_GetCurrentRSVPChangeList(pDatabase);
local vRSVPString = EventDatabase_PackRSVPRequest(pRSVP);
local vRSVPAltsString = EventDatabase_GetRSVPAltsString(pRSVP);
if vRSVPAltsString then
vRSVPString = vRSVPString.."/ALTS:"..vRSVPAltsString;
end
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_AddRSVPRequest: Adding string "..vRSVPString);
end
table.insert(vChangeList, vRSVPString);
GroupCalendar_MajorDatabaseChange(pDatabase);
end
function EventDatabase_GetRSVPOriginalDateTime(pRSVP)
if pRSVP.mOriginalDate then
return pRSVP.mOriginalDate, pRSVP.mOriginalTime;
else
return pRSVP.mDate, pRSVP.mTime;
end
end
function EventDatabase_RemoveAllRSVPsForEvent(pDatabase, pEvent, pOwnedDatabasesOnly)
local vPrefix = "EVT:"..pDatabase.UserName..","..pEvent.mID..",";
local vPrefixLength = string.len(vPrefix);
EventDatabase_RemoveAllRSVPsByPrefix(pDatabase.Realm, vPrefix, vPrefixLength, pOwnedDatabasesOnly);
end
function EventDatabase_RemoveAllRSVPsForDatabase(pDatabase, pOwnedDatabasesOnly)
local vPrefix = "EVT:"..pDatabase.UserName..",";
local vPrefixLength = string.len(vPrefix);
EventDatabase_RemoveAllRSVPsByPrefix(pDatabase.Realm, vPrefix, vPrefixLength, pOwnedDatabasesOnly);
end
function EventDatabase_RemoveAllRSVPsByPrefix(pRealm, pPrefix, pPrefixLength, pOwnedDatabasesOnly)
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if vDatabase.Realm == pRealm
and (not pOwnedDatabasesOnly or vDatabase.IsPlayerOwned) then
EventDatabase_RemoveRSVPsByPrefix(vDatabase, pPrefix, pPrefixLength);
end
end
end
function EventDatabase_RemoveRSVPsByPrefix(pDatabase, pPrefix, pPrefixLength)
local vRSVPString, vIndex, vRevision = EventDatabase_FindRSVPPrefixString(pDatabase, pPrefix, pPrefixLength)
while vRSVPString do
local vChangeList = pDatabase.RSVPs.ChangeList[vRevision];
table.remove(vChangeList, vIndex);
if table.getn(vChangeList) == 0 then
pDatabase.RSVPs.ChangeList[vRevision] = nil;
end
vRSVPString, vIndex, vRevision = EventDatabase_FindRSVPPrefixString(pDatabase, pPrefix, pPrefixLength)
end
end
function EventDatabase_ProcessRSVP(pDatabase, pRSVP)
local vEventDatabase = EventDatabase_GetDatabase(pRSVP.mOrganizerName, false);
-- Nothing to do if the database isn't one we own
if not vEventDatabase or not vEventDatabase.IsPlayerOwned then
return false;
end
-- Process the request into our database
local vEvent = EventDatabase_FindEventByID(vEventDatabase, pRSVP.mEventID);
if not vEvent then
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_ProcessRSVP: Discarding request from "..pDatabase.UserName.." for ".." event "..pRSVP.mEventID..": Event no longer exists");
end
return true; -- Have the request deleted
end
-- Look up an existing RSVP
local vExistingRSVP = EventDatabase_FindEventRSVP(pDatabase.UserName, vEvent, pRSVP.mName);
-- If the player has been banned (removed) from the event then ignore any
-- requests from them
if vExistingRSVP
and vExistingRSVP.mStatus == "-" then
return true; -- Delete the request without processing it
end
-- If the player is requesting attendance then figure out how to handle the request
if pRSVP.mStatus == "Y" then
-- If they're already accepted on the list then preserve their current
-- status
if vExistingRSVP
and (vExistingRSVP.mStatus == "Y"
or vExistingRSVP.mStatus == "S") then
pRSVP.mOriginalDate, pRSVP.mOriginalTime = EventDatabase_GetRSVPOriginalDateTime(vExistingRSVP);
pRSVP.mStatus = vExistingRSVP.mStatus;
-- Otherwise put them on standby if using manual confirmations
elseif vEvent.mManualConfirm then
pRSVP.mStatus = "S";
-- Check availablility to determine how to handle automatic confirmations
else
local vAvailableSlots = EventAvailableSlots_CountSlots(pDatabase, vEvent);
if not EventAvailableSlots_AcceptPlayer(vAvailableSlots, pRSVP.mClassCode) then
pRSVP.mStatus = "S";
end
end
end
-- Add the RSVP
EventDatabase_AddEventRSVP(vEventDatabase, vEvent, pDatabase.UserName, pRSVP);
return true;
end
function EventDatabase_AddRSVP(pDatabase, pRSVP)
if gGroupCalendar_Settings.Debug then
if not pRSVP.mName then
Calendar_DumpArray("Missing attendee: ", pRSVP);
return;
end
end
if not EventDatabase_ProcessRSVP(pDatabase, pRSVP) then
EventDatabase_AddRSVPRequest(pDatabase, pRSVP);
end
end
function EventDatabase_RemoveOldAttendeeRSVP(pAttendeeName, pOrganizerName, pEventID, pAttendanceString)
local vAttendeeDatabase = EventDatabase_GetDatabase(pAttendeeName, false);
-- Just leave if we've never heard of them
if not vAttendeeDatabase then
return;
end
-- Just leave if it's a delete request, we don't know how to handle these yet
if not pAttendanceString then
return;
end
-- Remove the RSVP request if it exists in their database
local vRSVP = EventDatabase_UnpackEventRSVP(pOrganizerName, pAttendeeName, pEventID, pAttendanceString);
EventDatabase_RemoveOlderRSVP(vAttendeeDatabase, vRSVP)
end
function EventDatabase_RemoveOlderRSVP(pDatabase, pRSVP)
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_RemoveOlderRSVP: Removing RSVP for "..pRSVP.mName.." from "..pDatabase.UserName..","..pRSVP.mEventID);
end
local vRSVPString, vIndex, vRevision = EventDatabase_FindRSVPRequestString(pDatabase, pRSVP.mOrganizerName, pRSVP.mEventID);
while vRSVPString ~= nil do
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_RemoveOlderRSVP: "..pRSVP.mOrganizerName..","..pRSVP.mEventID.." from position "..vRevision..","..vIndex);
end
-- If the existing RSVP is newer than the specified date/time then disregard the request
if pRSVP.mDate ~= nil then
local vRSVP = EventDatabase_UnpackRSVPRequest(vRSVPString, pRSVP.mName);
if vRSVP.mDate > pRSVP.mDate
or (vRSVP.mDate == pRSVP.mDate and vRSVP.mTime > pRSVP.mTime) then
if gGroupCalendar_Settings.Debug then
Calendar_DebugMessage("EventDatabase_RemoveOlderRSVP: Newer request already exists");
end
return false; -- Fail to indicate that a newer request is already in the database
end
end
-- Remove the old one
local vChangeList = pDatabase.RSVPs.ChangeList[vRevision];
table.remove(vChangeList, vIndex);
if table.getn(vChangeList) == 0 then
pDatabase.RSVPs.ChangeList[vRevision] = nil;
end
-- Keep removing in case the database has become corrupted with multiple copies
vRSVPString, vIndex, vRevision = EventDatabase_FindRSVPRequestString(pDatabase, pRSVP.mOrganizerName, pRSVP.mEventID);
end
return true; -- Everything's ok, no newer RSVP was found
end
function EventDatabase_FindRSVPRequestString(pDatabase, pOrganizerName, pEventID)
if not pEventID then
Calendar_DebugMessage("EventDatabase_FindRSVPRequestString: pEventID IS NIL!");
end
if not pOrganizerName then
Calendar_DebugMessage("EventDatabase_FindRSVPRequestString: pOrganizerName IS NIL!");
end
local vRSVPPrefix = "EVT:"..pOrganizerName..","..pEventID..",";
local vRSVPPrefixLength = string.len(vRSVPPrefix);
return EventDatabase_FindRSVPPrefixString(pDatabase, vRSVPPrefix, vRSVPPrefixLength);
end
function EventDatabase_FindRSVPPrefixString(pDatabase, pPrefixString, pPrefixLength)
local vRSVPs = EventDatabase_GetRSVPs(pDatabase);
for vRevision, vChangeList in vRSVPs.ChangeList do
local vNumChanges = table.getn(vChangeList);
for vIndex = 1, vNumChanges do
local vRSVP = vChangeList[vIndex];
if string.sub(vRSVP, 1, pPrefixLength) == pPrefixString then
return vRSVP, vIndex, vRevision;
end
end
end
return nil, nil, nil;
end
function EventDatabase_FindRSVPRequestData(pDatabase, pOrganizerName, pEventID)
if not pEventID then
Calendar_DebugMessage("EventDatabase_FindRSVPRequestData: pEventID is nil!");
end
if not pOrganizerName then
Calendar_DebugMessage("EventDatabase_FindRSVPRequestData: pOrganizerName IS NIL!");
end
local vRSVPString = EventDatabase_FindRSVPRequestString(pDatabase, pOrganizerName, pEventID);
if not vRSVPString then
return nil;
end
return EventDatabase_UnpackRSVPRequest(vRSVPString, pDatabase.UserName);
end
function EventDatabase_FindEventRSVPString(pEvent, pAttendeeName)
if not pEvent.mAttendance then
return nil;
end
return pEvent.mAttendance[pAttendeeName];
end
function EventDatabase_FindEventRSVP(pEventOwner, pEvent, pAttendeeName)
local vEventRSVPString = EventDatabase_FindEventRSVPString(pEvent, pAttendeeName);
if not vEventRSVPString then
return nil;
end
return EventDatabase_UnpackEventRSVP(pEventOwner, pAttendeeName, pEvent.ID, vEventRSVPString);
end
function EventDatabase_EventExists(pEventOwner, pEventID)
local vDatabase = EventDatabase_GetDatabase(pEventOwner, false);
if not vDatabase then
return false;
end
if not EventDatabase_FindEventByID(vDatabase, pEventID) then
return false;
end
return true;
end
function EventDatabase_RemoveObsoleteRSVPs(pDatabase)
local vRSVPs = EventDatabase_GetRSVPs(pDatabase);
for vRevision, vChangeList in vRSVPs.ChangeList do
local vNumChanges = table.getn(vChangeList);
local vIndex = 1;
while vIndex <= vNumChanges do
local vRSVP = EventDatabase_UnpackRSVPRequest(vChangeList[vIndex], pDatabase.UserName);
if not EventDatabase_EventExists(vRSVP.mOrganizerName, vRSVP.mEventID) then
table.remove(vChangeList, vIndex);
vNumChanges = vNumChanges - 1;
else
vIndex = vIndex + 1;
end
end
if vNumChanges == 0 then
vRSVPs.ChangeList[vRevision] = nil;
end
end
end
function EventDatabase_GetRSVPAltsString(pRSVP)
local vAltsString = nil;
if not pRSVP.mAlts then
return nil;
end
for vPlayerName, _ in pRSVP.mAlts do
if not vAltsString then
vAltsString = vPlayerName;
else
vAltsString = vAltsString..","..vPlayerName;
end
end
return vAltsString;
end
function EventDatabase_PackRSVPRequest(pRSVP)
local vRequest = "EVT:"..pRSVP.mOrganizerName..","..pRSVP.mEventID..","..pRSVP.mDate..","..pRSVP.mTime..","..pRSVP.mStatus..","..EventDatabase_PackCharInfo(pRSVP)..",";
if pRSVP.mComment then
vRequest = vRequest..pRSVP.mComment;
end
if pRSVP.mGuild then
vRequest = vRequest..","..pRSVP.mGuild..","..pRSVP.mGuildRank;
else
vRequest = vRequest..",,";
end
return vRequest;
end
function EventDatabase_UnpackRSVPRequest(pRSVPString, pAttendee)
local vCommands = CalendarNetwork_ParseCommandSubString("/"..pRSVPString);
local vOpcode = vCommands[1].opcode;
if vOpcode ~= "EVT" then
return false;
end
local vOperands = vCommands[1].operands;
return EventDatabase_UnpackRSVPFieldArray(vOperands, pAttendee);
end
function EventDatabase_FillInRSVPGuildInfo(pRSVP)
if pRSVP.mGuild then
return;
end
vIsInGuild, vRankIndex = CalendarNetwork_UserIsInSameGuild(pRSVP.mName);
if not vIsInGuild then
return;
end
pRSVP.mGuild = gGroupCalendar_PlayerGuild;
pRSVP.mGuildRank = vRankIndex;
end
function EventDatabase_UnpackRSVPFieldArray(pArray, pAttendee)
local vRSVP =
{
mOrganizerName = pArray[1],
mName = pAttendee;
mEventID = tonumber(pArray[2]),
mDate = tonumber(pArray[3]),
mTime = tonumber(pArray[4]),
mStatus = pArray[5],
mComment = pArray[7],
mGuild = pArray[8],
mGuildRank = tonumber(pArray[9]),
};
if vRSVP.mGuild == "" then
vRSVP.mGuild = nil;
end
EventDatabase_UnpackCharInfo(pArray[6], vRSVP);
EventDatabase_FillInRSVPGuildInfo(vRSVP);
return vRSVP;
end
function EventDatabase_PackEventRSVP(pEventRSVP)
local vEventRSVPString = ""..pEventRSVP.mDate..","..pEventRSVP.mTime..","..pEventRSVP.mStatus..","..EventDatabase_PackCharInfo(pEventRSVP)..",";
if pEventRSVP.mComment then
vEventRSVPString = vEventRSVPString..pEventRSVP.mComment;
end
if pEventRSVP.mGuild then
vEventRSVPString = vEventRSVPString..","..pEventRSVP.mGuild..","..pEventRSVP.mGuildRank;
else
vEventRSVPString = vEventRSVPString..",,";
end
if pEventRSVP.mOriginalDate then
vEventRSVPString = vEventRSVPString..","..pEventRSVP.mOriginalDate..","..pEventRSVP.mOriginalTime;
else
vEventRSVPString = vEventRSVPString..",,";
end
return vEventRSVPString;
end
function EventDatabase_UnpackEventRSVP(pOrganizerName, pAttendeeName, pEventID, pEventRSVPString)
local vEventParameters = CalendarNetwork_ParseParameterString(pEventRSVPString);
local vRSVPFields =
{
mOrganizerName = pOrganizerName,
mName = pAttendeeName,
mEventID = pEventID,
mDate = tonumber(vEventParameters[1]),
mTime = tonumber(vEventParameters[2]),
mStatus = vEventParameters[3],
mComment = vEventParameters[5],
mGuild = vEventParameters[6],
mGuildRank = tonumber(vEventParameters[7]),
mOriginalDate = tonumber(vEventParameters[8]),
mOriginalTime = tonumber(vEventParameters[9]),
};
if vRSVPFields.mGuild == "" then
vRSVPFields.mGuild = nil;
end
EventDatabase_UnpackCharInfo(vEventParameters[4], vRSVPFields);
EventDatabase_FillInRSVPGuildInfo(vRSVPFields);
return vRSVPFields;
end
function EventDatabase_PackCharInfo(pCharInfo)
local vRaceCode, vClassCode, vLevel;
vRaceCode = pCharInfo.mRaceCode;
if not vRaceCode then
vRaceCode = "?";
end
vClassCode = pCharInfo.mClassCode;
if not vClassCode then
vClassCode = "?";
end
if pCharInfo.mLevel then
vLevel = pCharInfo.mLevel;
else
vLevel = 0;
end
return vRaceCode..vClassCode..vLevel;
end
function EventDatabase_GetRaceCodeByRace(pRace)
for vRaceCode, vRaceInfo in gGroupCalendar_RaceNamesByRaceCode do
if pRace == vRaceInfo.name then
return vRaceCode;
end
end
return "?";
end
function EventDatabase_GetRaceByRaceCode(pRaceCode)
local vRaceInfo = gGroupCalendar_RaceNamesByRaceCode[pRaceCode];
if not vRaceInfo then
return nil;
end
return vRaceInfo.name;
end
function EventDatabase_GetClassCodeByClass(pClass)
for vClassCode, vClassInfo in gGroupCalendar_ClassInfoByClassCode do
if pClass == vClassInfo.name then
return vClassCode;
end
end
return "?";
end
function EventDatabase_GetClassByClassCode(pClassCode)
local vClassInfo = gGroupCalendar_ClassInfoByClassCode[pClassCode];
if not vClassInfo then
if pClassCode then
return "Unknown ("..pClassCode..")";
else
return "Unknown (nil)";
end
else
return vClassInfo.name;
end
end
function EventDatabase_UnpackCharInfo(pString, rCharInfo)
if not pString then
rCharInfo.mRaceCode = "?";
rCharInfo.mClassCode = "?";
rCharInfo.mLevel = 0;
else
rCharInfo.mRaceCode = string.sub(pString, 1, 1);
rCharInfo.mClassCode = string.sub(pString, 2, 2);
rCharInfo.mLevel = tonumber(string.sub(pString, 3));
end
end
function EventDatabase_IsQuestingEventType(pEventType)
return pEventType ~= "Meet" and pEventType ~= "Birth";
end
function EventDatabase_IsResetEventType(pEventType)
if not pEventType then
return false;
end
return gGroupCalendar_EventTypes.Reset.ResetEventInfo[pEventType] ~= nil;
end
function EventDatabase_GetResetIconCoords(pEventType)
if not pEventType then
return nil;
end
return gGroupCalendar_EventTypes.Reset.ResetEventInfo[pEventType];
end
function EventDatabase_GetResetEventLargeIconPath(pEventType)
if not pEventType then
return nil;
end
local vResetEventInfo = gGroupCalendar_EventTypes.Reset.ResetEventInfo[pEventType];
if vResetEventInfo.largeIcon then
return vResetEventInfo.largeIcon, false;
elseif vResetEventInfo.largeSysIcon then
return vResetEventInfo.largeSysIcon, true;
else
return nil;
end
end
function EventDatabase_IsDungeonResetEventType(pEventType)
if not pEventType then
return false;
end
local vResetEventInfo = gGroupCalendar_EventTypes.Reset.ResetEventInfo[pEventType];
if not vResetEventInfo then
return false;
end
return vResetEventInfo.isDungeon;
end
function EventDatabase_LookupDungeonResetEventTypeByName(pName)
for vEventType, vResetEventInfo in gGroupCalendar_EventTypes.Reset.ResetEventInfo do
if vResetEventInfo.isDungeon then
if vResetEventInfo.name == pName then
return vEventType;
end
end
end
return nil;
end
function EventDatabase_LookupTradeskillEventTypeByID(pID)
for vEventType, vResetEventInfo in gGroupCalendar_EventTypes.Reset.ResetEventInfo do
if vResetEventInfo.isTradeskill then
if vResetEventInfo.id == pID then
return vEventType;
end
end
end
return nil;
end
function EventDatabase_EventTypeUsesAttendance(pEventType)
if pEventType == "Birth"
or EventDatabase_IsResetEventType(pEventType) then
return false;
end
return true;
end
function EventDatabase_EventTypeUsesLevelLimits(pEventType)
if pEventType == "Birth"
or pEventType == "Meet"
or EventDatabase_IsResetEventType(pEventType) then
return false;
end
return true;
end
function EventDatabase_EventTypeUsesTime(pEventType)
if pEventType == "Birth" then
return false;
end
return true;
end
function CalendarChanges_New(pID)
local vID;
if pID then
vID = pID;
else
vID = Calendar_GetCurrentDateTimeUT60();
end
return
{
ID = vID,
Revision = 0,
AuthRevision = 0,
ChangeList = {},
};
end
function CalendarChanges_Rebuild(pChanges)
pChanges.ID = Calendar_GetCurrentDateTimeUT60();
pChanges.Revision = 0;
pChanges.AuthRevision = 0;
pChanges.ChangeList = {};
end
function CalendarChanges_Compact(pChanges)
local vNewChanges = nil;
for vRevision, vChanges in pChanges.ChangeList do
for vIndex, vChange in vChanges do
if not vNewChanges then
vNewChanges = {};
end
if type(vIndex) == "number" then
table.insert(vNewChanges, vChange);
end
end
end
pChanges.ID = Calendar_GetCurrentDateTimeUT60();
pChanges.ChangeList = {};
if vNewChanges then
pChanges.Revision = 1;
pChanges.AuthRevision = 0;
pChanges.ChangeList[1] = vNewChanges;
else
pChanges.Revision = 0;
pChanges.AuthRevision = 0;
end
end
function CalendarChanges_Open(pChanges, pRevision)
local vChangeList = pChanges.ChangeList[pRevision];
if not vChangeList then
vChangeList = {};
pChanges.ChangeList[pRevision] = vChangeList;
pChanges.Revision = pRevision;
end
vChangeList.IsOpen = true;
return vChangeList;
end
function CalendarChanges_Close(pChanges, pRevision)
local vChangeList = pChanges.ChangeList[pRevision];
if not vChangeList then
return;
end
vChangeList.IsOpen = nil;
end
function CalendarChanges_SetChangeList(pChanges, pRevision, pChangeList)
pChanges.ChangeList[pRevision] = pChangeList;
if pRevision > pChanges.Revision then
pChanges.Revision = pRevision;
end
end
function CalendarChanges_GetCurrentChangeList(pChanges)
local vChangeList = nil;
local vRevisionChanged = false;
if pChanges.Revision > 0 then
vChangeList = pChanges.ChangeList[pChanges.Revision];
end
if vChangeList == nil
or not vChangeList.IsOpen then
pChanges.Revision = pChanges.Revision + 1;
vChangeList = {};
pChanges.ChangeList[pChanges.Revision] = vChangeList;
vChangeList.IsOpen = true;
vRevisionChanged = true;
end
return vChangeList, vRevisionChanged;
end
function CalendarChanges_LockdownCurrentChangeList(pChanges)
-- Just return if there are no changes yet
if pChanges.Revision == 0 then
return;
end
-- See if the current list exists and is open
local vChangeList = pChanges.ChangeList[pChanges.Revision];
if not vChangeList
or not vChangeList.IsOpen then
return;
end
-- Close the change list
vChangeList.IsOpen = nil;
end
function CalendarChanges_GetRevisionPath(pLabel, pUserName, pDatabaseID, pRevision, pAuthRevision)
local vPath = pLabel..":"..pUserName..",";
if pDatabaseID then
vPath = vPath..pDatabaseID;
end
vPath = vPath..","..pRevision;
if pAuthRevision then
vPath = vPath..","..pAuthRevision;
end
return vPath.."/";
end
function CalendarChanges_IsEmpty(pChanges)
if not pChanges
or pChanges.Revision == 0 then
return true;
end
for vRevision, vChanges in pChanges.ChangeList do
return false;
end
return true;
end
function CalendarChanges_GetChangeList(pChanges, pRevision)
return pChanges.ChangeList[pRevision];
end
function CalendarAttendanceList_New()
return
{
NumCategories = 0,
NumPlayers = 0,
NumAttendees = 0,
Categories = {},
SortedCategories = {},
ClassTotals = {},
Items = {},
};
end
function CalendarAttendanceList_RemoveCategory(pAttendanceList, pCategoryID)
local vClassInfo = pAttendanceList.Categories[pCategoryID];
if not vClassInfo then
return false;
end
pAttendanceList.NumPlayers = pAttendanceList.NumPlayers - table.getn(vClassInfo.mAttendees);
pAttendanceList.NumCategories = pAttendanceList.NumCategories - 1;
-- Remove it from the sorted categories
for vIndex, vCategoryID in pAttendanceList.SortedCategories do
if vCategoryID == pCategoryID then
table.remove(pAttendanceList.SortedCategories, vIndex);
end
end
pAttendanceList.Categories[pCategoryID] = nil;
return true;
end
function CalendarAttendanceList_AddItem(pAttendanceList, pCategoryID, pItem)
if not pItem then
Calendar_ErrorMessage("CalendarAttendanceList_AddItem: pItem is nil");
return;
end
if not pCategoryID then
Calendar_ErrorMessage("CalendarAttendanceList_AddItem: pCategoryID is nil");
return;
end
local vClassInfo = pAttendanceList.Categories[pCategoryID];
if not vClassInfo then
vClassInfo = {mCount = 1, mClassCode = pCategoryID, mAttendees = {}};
pAttendanceList.Categories[pCategoryID] = vClassInfo;
table.insert(pAttendanceList.SortedCategories, pCategoryID);
pAttendanceList.NumCategories = pAttendanceList.NumCategories + 1;
else
vClassInfo.mCount = vClassInfo.mCount + 1;
end
pAttendanceList.NumPlayers = pAttendanceList.NumPlayers + 1;
table.insert(vClassInfo.mAttendees, pItem);
end
function CalendarAttendanceList_AddPlayer(pAttendanceList, pPlayer)
return CalendarAttendanceList_AddItem(pAttendanceList, pPlayer.mClassCode, pPlayer);
end
function CalendarAttendanceList_AddWhisper(pAttendanceList, pPlayerName, pWhispers)
local vPlayer =
{
mName = pPlayerName,
mWhispers = pWhispers.mWhispers,
};
local vGuildMemberIndex = CalendarNetwork_GetGuildMemberIndex(pPlayerName);
if vGuildMemberIndex then
local vMemberName, vRank, vRankIndex,
vLevel, vClass, vZone, vNote,
vOfficerNote, vOnline = GetGuildRosterInfo(vGuildMemberIndex);
vPlayer.mLevel = vLevel;
vPlayer.mClassCode = EventDatabase_GetClassCodeByClass(vClass);
vPlayer.mZone = vZone;
vPlayer.mOnline = vOnline;
end
vPlayer.mDate = pWhispers.mDate;
vPlayer.mTime = pWhispers.mTime;
vPlayer.mType = "Whisper";
return CalendarAttendanceList_AddItem(
pAttendanceList,
"WHISPERS",
vPlayer);
end
function CalendarAttendanceList_AddEventAttendanceItems(pAttendanceList, pDatabase, pEvent)
if not pEvent.mAttendance then
return;
end
for vAttendeeName, vRSVPString in pEvent.mAttendance do
local vRSVP = EventDatabase_UnpackEventRSVP(pDatabase.UserName, vAttendeeName, pEvent.mID, vRSVPString);
pAttendanceList.Items[vRSVP.mName] = vRSVP;
end
end
function CalendarAttendanceList_AddPendingRequests(pAttendanceList, pDatabase, pEvent)
for vRealmUser, vDatabase in gGroupCalendar_Database.Databases do
if EventDatabase_DatabaseIsVisible(vDatabase) then
local vPendingRSVP = EventDatabase_FindRSVPRequestData(vDatabase, pDatabase.UserName, pEvent.mID);
if vPendingRSVP then
if vPendingRSVP.mStatus == "Y" then
vPendingRSVP.mStatus = "P";
end
CalendarAttendanceList_AddItem(pAttendanceList, "PENDING", vPendingRSVP);
end
end
end
end
function CalendarAttendanceList_CalculateClassTotals(pAttendanceList, pIsAttendingFunction)
pAttendanceList.ClassTotals = {};
for vName, vItem in pAttendanceList.Items do
if vItem.mClassCode
and pIsAttendingFunction(vItem) then
local vTotal = pAttendanceList.ClassTotals[vItem.mClassCode];
if not vTotal then
pAttendanceList.ClassTotals[vItem.mClassCode] = 1;
else
pAttendanceList.ClassTotals[vItem.mClassCode] = vTotal + 1;
end
end
end
end
function CalendarAttendanceList_RSVPIsAttending(pItem)
return pItem.mStatus ~= "-"
and pItem.mStatus ~= "N"
and pItem.mStatus ~= "C";
end
function CalendarAttendanceList_FindItem(pAttendanceList, pFieldName, pFieldValue, pCategoryID)
if not pAttendanceList then
return nil;
end
if not pFieldValue then
Calendar_DebugMessage("CalendarAttendanceList_FindItem: pFieldValue is nil for "..pFieldName);
return nil;
end
local vLowerFieldValue = strlower(pFieldValue);
-- Search all categories if none is specified
if not pCategoryID then
for vCategoryID, vCategoryInfo in pAttendanceList.Categories do
for vIndex, vItem in vCategoryInfo.mAttendees do
local vItemFieldValue = vItem[pFieldName];
if vItemFieldValue
and strlower(vItemFieldValue) == vLowerFieldValue then
return vItem;
end
end
end
-- Search the specified category
else
local vCategoryInfo = pAttendanceList.Categories[pCategoryID];
if not vCategoryInfo then
return nil;
end
for vIndex, vItem in vCategoryInfo.mAttendees do
if strlower(vItem[pFieldName]) == vLowerFieldValue then
return vItem;
end
end
end
return nil;
end
GroupCalendar_cSortByFlags =
{
Date = {Class = true, Rank = false},
Rank = {Class = true, Rank = true},
Name = {Class = false, Rank = false, Name = true},
Status = {Class = true, Rank = false},
ClassRank = {Class = true, Rank = true},
DateRank = {Class = true, Rank = true},
};
function CalendarAttendanceList_SortIntoCategories(pAttendanceList, pGetItemCategoryFunction)
-- Clear the existing categories
pAttendanceList.Categories = {};
pAttendanceList.SortedCategories = {};
--
local vTotalAttendees = 0;
for vName, vItem in pAttendanceList.Items do
local vCategoryID = pGetItemCategoryFunction(vItem);
if vCategoryID then
if vCategoryID ~= "NO" then
vTotalAttendees = vTotalAttendees + 1;
end
CalendarAttendanceList_AddItem(pAttendanceList, pGetItemCategoryFunction(vItem), vItem);
end
end
pAttendanceList.NumAttendees = vTotalAttendees;
end
function CalendarAttendanceList_GetRSVPStatusCategory(pItem)
-- Skip RSVPs which are supposed to be ignored
if pItem.mStatus == "-"
or pItem.mStatus == "C" then
return nil;
end
if pItem.mStatus == "N" then
return "NO";
elseif pItem.mStatus == "S" then
return "STANDBY";
elseif pItem.mStatus == "Q" then
return "QUEUED";
else
return "YES";
end
end
function CalendarAttendanceList_GetRSVPClassCategory(pItem)
local vCategoryID = CalendarAttendanceList_GetRSVPStatusCategory(pItem);
if not vCategoryID then
return nil;
end
if vCategoryID ~= "YES" then
return vCategoryID;
end
if pItem.mClassCode then
return pItem.mClassCode;
end
return "?";
end
function CalendarAttendanceList_GetRSVPRankCategory(pItem)
local vCategoryID = CalendarAttendanceList_GetRSVPStatusCategory(pItem);
if not vCategoryID then
return nil;
end
if vCategoryID ~= "YES" then
return vCategoryID;
end
vCategoryID = EventDatabase_MapGuildRank(pItem.mGuild, pItem.mGuildRank);
if vCategoryID then
return vCategoryID;
end
return "?";
end
function CalendarEvent_GetAttendanceCounts(pDatabase, pEvent, pUseClassCategories)
local vAttendanceList = CalendarAttendanceList_New();
-- Fill in the items list
CalendarAttendanceList_AddEventAttendanceItems(vAttendanceList, pDatabase, pEvent);
-- Sort into categories
local vGetItemCategoryFunction;
if pUseClassCategories then
vGetItemCategoryFunction = CalendarAttendanceList_GetRSVPClassCategory;
else
vGetItemCategoryFunction = CalendarAttendanceList_GetRSVPStatusCategory;
end
CalendarAttendanceList_SortIntoCategories(vAttendanceList, vGetItemCategoryFunction);
-- Add pending requests
CalendarAttendanceList_AddPendingRequests(vAttendanceList, pDatabase, pEvent);
-- Calculate class totals
CalendarAttendanceList_CalculateClassTotals(vAttendanceList, CalendarAttendanceList_RSVPIsAttending);
-- Done
return vAttendanceList;
end
function CalendarEvent_SortAttendanceCounts(pAttendanceCounts, pSortBy)
local vSortByClass, vSortByRank, vSortByName;
if pSortBy then
local vSortByFlags = GroupCalendar_cSortByFlags[pSortBy];
if not vSortByFlags then
Calendar_ErrorMessage("CalendarEvent_SortAttendanceCounts: Unknown sort "..pSortBy);
return;
end
vSortByClass = vSortByFlags.Class;
vSortByRank = vSortByFlags.Rank;
vSortByName = vSortByFlags.Name;
else
vSortByClass = EventDatabase_IsQuestingEventType(pEvent.mType);
vSortByRank = false;
vSortByName = false;
end
-- Sort the categories
if vSortByClass then
table.sort(pAttendanceCounts.SortedCategories, EventDatabase_CompareClassCodes);
else
table.sort(pAttendanceCounts.SortedCategories, EventDatabase_CompareRankCodes);
end
-- Sort the attendance within each category
local vCompareFunction;
if vSortByName then
vCompareFunction = EventDatabase_CompareRSVPsByName;
elseif vSortByClass and vSortByRank then
vCompareFunction = EventDatabase_CompareRSVPsByRankAndDate;
else
vCompareFunction = EventDatabase_CompareRSVPsByDate;
end
if vSortByClass and vSortByRank then
end
for vCategory, vClassInfo in pAttendanceCounts.Categories do
table.sort(vClassInfo.mAttendees, vCompareFunction);
end
end
function EventAvailableSlots_InitializeFromLimits(pLimits)
local vAvailableSlots = {ClassInfo = {}};
local vMinTotal = 0;
for vClassCode, vClassCodeInfo in gGroupCalendar_ClassInfoByClassCode do
local vClassAvailable = nil;
local vClassExtrasAvailable = nil;
if pLimits
and pLimits.mClassLimits then
local vClassLimits = pLimits.mClassLimits[vClassCode];
if vClassLimits then
if vClassLimits.mMin then
vClassAvailable = vClassLimits.mMin;
if vClassAvailable < 0 then
vClassAvailable = 0;
end
vMinTotal = vMinTotal + vClassLimits.mMin;
end
if vClassLimits.mMax then
vClassExtrasAvailable = vClassLimits.mMax;
if vClassAvailable then
vClassExtrasAvailable = vClassExtrasAvailable - vClassAvailable;
end
if vClassExtrasAvailable < 0 then
vClassExtrasAvailable = 0;
end
end
vClassMax = vClassLimits.mMax;
end
end
if vClassAvailable
or vClassExtrasAvailable then
vAvailableSlots.ClassInfo[vClassCode] = {};
vAvailableSlots.ClassInfo[vClassCode].Available = vClassAvailable;
vAvailableSlots.ClassInfo[vClassCode].ExtrasAvailable = vClassExtrasAvailable;
end
end
if pLimits
and pLimits.mMaxAttendance then
vAvailableSlots.TotalExtras = pLimits.mMaxAttendance - vMinTotal;
if vAvailableSlots.TotalExtras < 0 then
vAvailableSlots.TotalExtras = 0;
end
else
vAvailableSlots.TotalExtras = nil;
end
return vAvailableSlots;
end
function CalendarEvent_PlayerClassAdded(pAvailableSlots, pClassCode)
CalendarEvent_PlayerClassMultiAdded(pAvailableSlots, pClassCode, 1);
end
function CalendarEvent_PlayerClassMultiAdded(pAvailableSlots, pClassCode, pNumAdded)
local vNumAdded = pNumAdded;
local vClassInfo = pAvailableSlots.ClassInfo[pClassCode];
if vNumAdded == 0 then
return;
end
-- If the class hasn't reached its minimum yet then accept the request
if vClassInfo
and vClassInfo.Available
and vClassInfo.Available > 0 then
local vAvailableUsed = vNumAdded;
if vAvailableUsed > vClassInfo.Available then
vAvailableUsed = vClassInfo.Available;
end
vClassInfo.Available = vClassInfo.Available - vAvailableUsed;
vNumAdded = vNumAdded - vAvailableUsed;
if vNumAdded == 0 then
return;
end
end
-- Nothing to do if there are no limits
if not pAvailableSlots.TotalExtras then
return;
end
-- Have to bail if total extras is now zero
if pAvailableSlots.TotalExtras == 0 then
return;
end
-- Decrease the space for the class
if vClassInfo
and vClassInfo.ExtrasAvailable
and vClassInfo.ExtrasAvailable > 0 then
if vNumAdded > vClassInfo.ExtrasAvailable then
vNumAdded = vClassInfo.ExtrasAvailable;
end
vClassInfo.ExtrasAvailable = vClassInfo.ExtrasAvailable - vNumAdded;
end
-- Decrease the total available extras
pAvailableSlots.TotalExtras = pAvailableSlots.TotalExtras - vNumAdded;
end
function EventAvailableSlots_AcceptPlayer(pAvailableSlots, pClassCode)
local vClassInfo = pAvailableSlots.ClassInfo[pClassCode];
-- If the class hasn't reached its minimum yet then accept the request
if vClassInfo
and vClassInfo.Available
and vClassInfo.Available > 0 then
vClassInfo.Available = vClassInfo.Available - 1;
return true;
end
-- If the minimum has been reached and the extra slots haven't all
-- been filled then accept the request
if pAvailableSlots.TotalExtras then
-- Put them on standby if the extras slots have all been filled
if pAvailableSlots.TotalExtras == 0 then
return false;
end
-- If the class has a max and it's been reached then put them
-- on standby
if vClassInfo
and vClassInfo.ExtrasAvailable then
if vClassInfo.ExtrasAvailable == 0 then
return false;
end
vClassInfo.ExtrasAvailable = vClassInfo.ExtrasAvailable - 1;
end
pAvailableSlots.TotalExtras = pAvailableSlots.TotalExtras - 1;
return true;
end
-- No limits at all, just accept them
return true;
end
function EventAvailableSlots_CountSlots(pDatabase, pEvent)
local vAvailableSlots = EventAvailableSlots_InitializeFromLimits(pEvent.mLimits);
local vAttendanceCounts = CalendarEvent_GetAttendanceCounts(pDatabase, pEvent, true);
for vCategory, vClassInfo in vAttendanceCounts.Categories do
if vCategory ~= "NO"
and vCategory ~= "STANDBY" then
CalendarEvent_PlayerClassMultiAdded(vAvailableSlots, vCategory, table.getn(vClassInfo.mAttendees));
end
end
return vAvailableSlots;
end
function EventDatabase_CompareRSVPsByDate(pRSVP1, pRSVP2)
local vRSVP1Date, vRSVP1Time = EventDatabase_GetRSVPOriginalDateTime(pRSVP1);
local vRSVP2Date, vRSVP2Time = EventDatabase_GetRSVPOriginalDateTime(pRSVP2);
if not vRSVP1Date then
return false;
elseif not vRSVP2Date then
return true;
end
if vRSVP1Date < vRSVP2Date then
return true;
elseif vRSVP1Date > vRSVP2Date then
return false;
elseif vRSVP1Time ~= vRSVP2Time then
return vRSVP1Time < vRSVP2Time;
else
return EventDatabase_CompareRSVPsByName(pRSVP1, pRSVP2);
end
end
function EventDatabase_CompareRSVPsByName(pRSVP1, pRSVP2)
return pRSVP1.mName < pRSVP2.mName;
end
function EventDatabase_CompareRSVPsByRankAndDate(pRSVP1, pRSVP2)
local vRank1 = EventDatabase_MapGuildRank(pRSVP1.mGuild, pRSVP1.mGuildRank);
local vRank2 = EventDatabase_MapGuildRank(pRSVP2.mGuild, pRSVP2.mGuildRank);
if not vRank1 then
if not vRank2 then
return EventDatabase_CompareRSVPsByDate(pRSVP1, pRSVP2);
else
return false;
end
elseif not vRank2 then
return true;
end
if vRank1 == vRank2 then
return EventDatabase_CompareRSVPsByDate(pRSVP1, pRSVP2);
else
return vRank1 < vRank2;
end
end
Calendar_cClassCodeSortOrder =
{
WHISPERS = 4,
PENDING = 3,
QUEUED = 2,
YES = 1,
STANDBY = -1,
NO = -2,
};
function EventDatabase_CompareClassCodes(pClassCode1, pClassCode2)
local vSortPriority1 = Calendar_cClassCodeSortOrder[pClassCode1];
local vSortPriority2 = Calendar_cClassCodeSortOrder[pClassCode2];
if not vSortPriority1 then
if not vSortPriority2 then
return EventDatabase_GetClassByClassCode(pClassCode1) < EventDatabase_GetClassByClassCode(pClassCode2);
else
return vSortPriority2 < 0;
end
elseif not vSortPriority2 then
return vSortPriority1 > 0;
else
return vSortPriority1 > vSortPriority2;
end
end
function EventDatabase_CompareRankCodes(pRank1, pRank2)
local vIsRank1 = type(pRank1) == "number";
local vIsRank2 = type(pRank2) == "number";
if vIsRank1 and vIsRank2 then
return pRank1 < pRank2;
end
if not vIsRank1 then
if not vIsRank2 then
return EventDatabase_CompareClassCodes(pRank1, pRank2);
else
return false;
end
end
return true;
end
function EventDatabase_CreatePlayerRSVP(
pDatabase, pEvent,
pPlayerName,
pPlayerRace, pPlayerClass, pPlayeLevel,
pStatus,
pComment,
pGuild,
pGuildRank,
pAlts)
local vDate, vTime60 = EventDatabase_GetServerDateTime60Stamp();
local vAlts = nil;
if pAlts then
for vPlayerName, _ in pAlts do
if vPlayerName ~= pPlayerName then
if not vAlts then
vAlts = {};
end
vAlts[vPlayerName] = true;
end
end
end
return
{
mName = pPlayerName,
mOrganizerName = pDatabase.UserName,
mEventID = pEvent.mID,
mDate = vDate,
mTime = vTime60,
mStatus = pStatus,
mComment = pComment,
mRaceCode = pPlayerRace,
mClassCode = pPlayerClass,
mLevel = pPlayeLevel,
mGuild = pGuild,
mGuildRank = pGuildRank,
mAlts = vAlts,
};
end
function EventDatabase_PlayerLevelChanged(pPlayerLevel)
if not gGroupCalendar_UserDatabase then
return;
end
gGroupCalendar_UserDatabase.PlayerLevel = pPlayerLevel;
end
function EventDatabase_PlayerIsQualifiedForEvent(pEvent, pPlayerLevel)
if not pPlayerLevel then
return false;
end
if pEvent.mMinLevel and
pPlayerLevel < pEvent.mMinLevel then
return false;
end
if pEvent.mMaxLevel and
pPlayerLevel > pEvent.mMaxLevel then
return false;
end
return true;
end
function EventDatabase_RescheduleEvent(pDatabase, pEvent, pNewDate)
local vNewEvent = EventDatabase_NewEvent(pDatabase, pNewDate);
vNewEvent.mType = pEvent.mType;
vNewEvent.mTitle = pEvent.mTitle;
vNewEvent.mTime = pEvent.mTime;
vNewEvent.mDuration = pEvent.mDuration;
vNewEvent.mDescription = pEvent.mDescription;
vNewEvent.mMinLevel = pEvent.mMinLevel;
vNewEvent.mAttendance = pEvent.mAttendance;
EventDatabase_AddEvent(pDatabase, vNewEvent);
return EventDatabase_DeleteEvent(pDatabase, pEvent);
end
function EventDatabase_DeleteOldEvents(pDatabase)
if not pDatabase.Events then
return;
end
for vDate, vEvents in pDatabase.Events do
if vDate < gGroupCalendar_MinimumEventDate then
-- Remove or reschedule the events for this date
local vNumEvents = table.getn(vEvents);
local vEventIndex = 1;
for vIndex = 1, vNumEvents do
local vEvent = vEvents[vEventIndex];
if pDatabase.IsPlayerOwned and vEvent.mType == "Birth" then
Calendar_DebugMessage("GroupCalendar: Rescheduling birthday event "..vEvent.mID.." for "..pDatabase.UserName);
local vMonth, vDay, vYear = Calendar_ConvertDateToMDY(vDate);
vYear = vYear + 1;
local vNewDate = Calendar_ConvertMDYToDate(vMonth, vDay, vYear);
if not EventDatabase_RescheduleEvent(pDatabase, vEvent, vNewDate) then
Calendar_DebugMessage("GroupCalendar: Can't reschedule event "..vEvent.mID.." for "..pDatabase.UserName..": Unknown error");
vEventIndex = vEventIndex + 1;
end
elseif not EventDatabase_DeleteEvent(pDatabase, vEvent) then
Calendar_DebugMessage("GroupCalendar: Can't delete old event "..vEvent.mID.." for "..pDatabase.UserName..": Unknown error");
vEventIndex = vEventIndex + 1;
end
end
end
end
end
function EventDatabase_PlayerIsAttendingEvent(pEventOwner, pEvent)
for vPlayerName, vPlayerValue in gGroupCalendar_PlayerCharacters do
local vPlayerDatabase = EventDatabase_GetDatabase(vPlayerName, false);
local vRSVP = nil;
if vPlayerDatabase then
vRSVP = EventDatabase_FindRSVPRequestData(vPlayerDatabase, pEventOwner, pEvent.mID);
end
if not vRSVP then
vRSVP = EventDatabase_FindEventRSVP(pEventOwner, pEvent, vPlayerName);
end
if vRSVP then
local vStatus1 = string.sub(vRSVP.mStatus, 1, 1);
if vStatus1 == "Y" then
return true;
end
end
end
return false;
end
function EventDatabase_RemoveSavedInstanceEvents(pDatabase)
for vDate, vSchedule in pDatabase.Events do
local vEventIndex = 1;
local vNumEvents = table.getn(vSchedule);
while vEventIndex <= vNumEvents do
local vEvent = vSchedule[vEventIndex];
if EventDatabase_IsDungeonResetEventType(vEvent.mType) then
EventDatabase_DeleteEvent(pDatabase, vEvent);
vNumEvents = vNumEvents - 1;
else
vEventIndex = vEventIndex + 1;
end
end
end
end
function EventDatabase_RemoveTradeskillEventByType(pDatabase, pEventType)
for vDate, vSchedule in pDatabase.Events do
local vEventIndex = 1;
local vNumEvents = table.getn(vSchedule);
while vEventIndex <= vNumEvents do
local vEvent = vSchedule[vEventIndex];
if vEvent.mType == pEventType then
EventDatabase_DeleteEvent(pDatabase, vEvent);
vNumEvents = vNumEvents - 1;
else
vEventIndex = vEventIndex + 1;
end
end
end
end
function EventDatabase_ScheduleResetEvent(pDatabase, pType, pResetDate, pResetTime)
local vEvent = EventDatabase_NewEvent(pDatabase, pResetDate);
vEvent.mType = pType;
vEvent.mPrivate = true;
vEvent.mTime = pResetTime;
vEvent.mDuration = nil;
EventDatabase_AddEvent(pDatabase, vEvent);
end
function EventDatabase_ScheduleSavedInstanceEvent(pDatabase, pName, pResetDate, pResetTime)
local vType = EventDatabase_LookupDungeonResetEventTypeByName(pName);
if not vType then
Calendar_DebugMessage("GroupCalendar: Can't schedule reset event for "..pName..": The instance name is not recognized");
return;
end
EventDatabase_ScheduleResetEvent(pDatabase, vType, pResetDate, pResetTime);
end
function EventDatabase_ScheduleTradeskillCooldownEvent(pDatabase, pTradeskillID, pCooldownSeconds)
local vType = EventDatabase_LookupTradeskillEventTypeByID(pTradeskillID);
local vResetDate, vResetTime = Calendar_GetServerDateTimeFromSecondsOffset(pCooldownSeconds);
EventDatabase_RemoveTradeskillEventByType(pDatabase, vType);
EventDatabase_ScheduleResetEvent(pDatabase, vType, vResetDate, vResetTime);
end
function EventDatabase_UpdateTradeskillCooldown(pDatabase, pTradeskillID)
local vCooldown = Calendar_GetTradeskillCooldown(pTradeskillID);
if vCooldown then
EventDatabase_ScheduleTradeskillCooldownEvent(pDatabase, pTradeskillID, vCooldown)
end
end
function EventDatabase_UpdateCurrentTradeskillCooldown()
local vTradeskillName, vCurrentLevel, vMaxLevel = GetTradeSkillLine();
if not vTradeskillName then
return;
end
local vTradeskillID = Calendar_LookupTradeskillIDByName(vTradeskillName);
if not vTradeskillID then
return;
end
EventDatabase_UpdateTradeskillCooldown(gGroupCalendar_UserDatabase, vTradeskillID);
end
function EventDatabase_MapGuildRank(pFromGuild, pFromRank)
if not pFromGuild
or not pFromRank then
return nil;
end
-- If it's the same guild then just return the rank
if pFromGuild == gGroupCalendar_PlayerGuild then
return pFromRank;
end
-- Force to zero if not in any guild
if not IsInGuild() then
return nil;
end
-- Just cover our eyes if the roster isn't loaded yet
if GetNumGuildMembers() == 0 then
CalendarNetwork_LoadGuildRoster();
return pFromRank;
end
local vMaxGuildRank = GuildControlGetNumRanks() - 1;
-- Get the mapping
local vToRankMap;
if gGroupCalendar_RealmSettings.RankMap then
vToRankMap = gGroupCalendar_RealmSettings.RankMap[gGroupCalendar_PlayerGuild];
end
local vRankMap;
if vToRankMap then
vRankMap = vToRankMap[pFromGuild];
end
if vRankMap then
local vToRank = vRankMap[pFromRank];
if vToRank then
return vToRank;
end
-- If there's not a mapping for this rank, map it to the
-- same value as the next highest rank
for vFromRank, vToRank in vRankMap do
if vFromRank > pFromRank then
return vToRank;
end
end
end
-- Do a dumb mapping which simply ensures that the rank index
-- is valid for the current guild
if pFromRank > vMaxGuildRank then
return vMaxGuildRank;
else
return pFromRank;
end
end
function EventDatabase_SetGuildRankMapping(pFromGuild, pFromRank, pToRank)
if not pFromGuild
or pFromGuild == ""
or not pFromRank then
return;
end
-- If it's the same guild then there's nothing to do
if pFromGuild == gGroupCalendar_PlayerGuild then
return;
end
-- Make sure the maps exist
if not gGroupCalendar_RealmSettings.RankMap then
gGroupCalendar_RealmSettings.RankMap = {};
end
-- Make sure the to guild map exists
local vToGuildMap = gGroupCalendar_RealmSettings.RankMap[gGroupCalendar_PlayerGuild];
if not vToGuildMap then
vToGuildMap = {};
gGroupCalendar_RealmSettings.RankMap[gGroupCalendar_PlayerGuild] = vToGuildMap;
end
-- Make sure the from guild map exists
local vGuildMap = vToGuildMap[pFromGuild];
if not vGuildMap then
vGuildMap = {};
vToGuildMap[pFromGuild] = vGuildMap;
end
vGuildMap[pFromRank] = pToRank;
end
function EventDatabase_UpdateGuildRankCache()
if not gGroupCalendar_PlayerGuild
or not gGroupCalendar_Initialized then
return;
end
if not gGroupCalendar_RealmSettings.GuildRanks then
gGroupCalendar_RealmSettings.GuildRanks = {};
end
vGuildRanks = {};
local vNumRanks = GuildControlGetNumRanks();
for vIndex = 1, vNumRanks do
vGuildRanks[vIndex - 1] = GuildControlGetRankName(vIndex);
end
gGroupCalendar_RealmSettings.GuildRanks[gGroupCalendar_PlayerGuild] = vGuildRanks;
end