diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index 3c275fc0..7db51905 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -93,13 +93,14 @@
+
-
+
diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs
index 12e82dde..62e9779b 100644
--- a/FFXIVClassic Map Server/WorldManager.cs
+++ b/FFXIVClassic Map Server/WorldManager.cs
@@ -41,8 +41,10 @@ namespace FFXIVClassic_Map_Server
private const int MILIS_LOOPTIME = 10;
private Timer mZoneTimer;
- //Content Groups
+ //Zone Server Groups
public Dictionary mContentGroups = new Dictionary();
+ public Dictionary mRelationGroups = new Dictionary();
+ public Dictionary mTradeGroups = new Dictionary();
private Object groupLock = new Object();
public ulong groupIndexId = 1;
@@ -712,9 +714,7 @@ namespace FFXIVClassic_Map_Server
player.SendInstanceUpdate();
player.playerSession.LockUpdates(false);
-
-
-
+
LuaEngine.GetInstance().CallLuaFunction(player, contentArea, "onZoneIn", true);
}
@@ -863,6 +863,160 @@ namespace FFXIVClassic_Map_Server
}
}
+ public RelationGroup CreateRelationGroup(Actor inviter, Actor invitee, ulong groupType)
+ {
+ lock (groupLock)
+ {
+ groupIndexId = groupIndexId | 0x0000000000000000;
+
+ RelationGroup group = new RelationGroup(groupIndexId, inviter.actorId, invitee.actorId, 0, groupType);
+ mRelationGroups.Add(groupIndexId, group);
+ groupIndexId++;
+
+ group.SendGroupPacketsAll(inviter.actorId, invitee.actorId);
+
+ return group;
+ }
+ }
+
+ public RelationGroup GetRelationGroup(uint actorId)
+ {
+ lock (groupLock)
+ {
+ foreach (RelationGroup relation in mRelationGroups.Values)
+ {
+ if (relation.GetHost() == actorId || relation.GetOther() == actorId)
+ return relation;
+ }
+ return null;
+ }
+ }
+
+ public void DeleteRelationGroup(ulong groupid)
+ {
+ lock (groupLock)
+ {
+ if (mRelationGroups.ContainsKey(groupid))
+ mRelationGroups.Remove(groupid);
+ }
+ }
+
+ public TradeGroup CreateTradeGroup(Player inviter, Player invitee)
+ {
+ lock (groupLock)
+ {
+ groupIndexId = groupIndexId | 0x0000000000000000;
+
+ TradeGroup group = new TradeGroup(groupIndexId, inviter.actorId, invitee.actorId);
+ mTradeGroups.Add(groupIndexId, group);
+ groupIndexId++;
+
+ group.SendGroupPacketsAll(inviter.actorId, invitee.actorId);
+
+ inviter.SendGameMessage(GetActor(), 25101, 0x20, (object)invitee); //You request to trade with X
+ invitee.SendGameMessage(GetActor(), 25037, 0x20, (object)inviter); //X wishes to trade with you
+
+ return group;
+ }
+ }
+
+ public TradeGroup GetTradeGroup(uint actorId)
+ {
+ lock (groupLock)
+ {
+ foreach (TradeGroup group in mTradeGroups.Values)
+ {
+ if (group.GetHost() == actorId || group.GetOther() == actorId)
+ return (TradeGroup)group;
+ }
+ return null;
+ }
+ }
+
+ public void DeleteTradeGroup(ulong groupid)
+ {
+ lock (groupLock)
+ {
+ if (mTradeGroups.ContainsKey(groupid))
+ {
+ TradeGroup group = mTradeGroups[groupid];
+ group.SendDeletePackets(group.GetHost(), group.GetOther());
+ mTradeGroups.Remove(groupid);
+ }
+ }
+ }
+
+ public void AcceptTrade(Player invitee)
+ {
+ TradeGroup group = GetTradeGroup(invitee.actorId);
+
+ if (group == null)
+ {
+ invitee.SendMessage(0x20, "", "MASSIVE ERROR: No tradegroup found!!!");
+ return;
+ }
+
+ Player inviter = (Player)invitee.GetZone().FindActorInArea(group.GetHost());
+
+ DeleteTradeGroup(group.groupIndex);
+ }
+
+ public void CancelTradeTooFar(Player inviter)
+ {
+ TradeGroup group = GetTradeGroup(inviter.actorId);
+
+ if (group == null)
+ {
+ inviter.SendMessage(0x20, "", "MASSIVE ERROR: No tradegroup found!!!");
+ return;
+ }
+
+ Player invitee = (Player)inviter.GetZone().FindActorInArea(group.GetOther());
+
+ inviter.SendGameMessage(GetActor(), 25042, 0x20); //You cancel the trade.
+ if (invitee != null)
+ invitee.SendGameMessage(GetActor(), 25042, 0x20); //The trade has been canceled.
+
+ DeleteTradeGroup(group.groupIndex);
+ }
+
+ public void CancelTrade(Player inviter)
+ {
+ TradeGroup group = GetTradeGroup(inviter.actorId);
+
+ if (group == null)
+ {
+ inviter.SendMessage(0x20, "", "MASSIVE ERROR: No tradegroup found!!!");
+ return;
+ }
+
+ Player invitee = (Player)inviter.GetZone().FindActorInArea(group.GetOther());
+
+ inviter.SendGameMessage(GetActor(), 25041, 0x20); //You cancel the trade.
+ if (invitee != null)
+ invitee.SendGameMessage(GetActor(), 25040, 0x20); //The trade has been canceled.
+
+ DeleteTradeGroup(group.groupIndex);
+ }
+
+ public void RefuseTrade(Player invitee)
+ {
+ TradeGroup group = GetTradeGroup(invitee.actorId);
+
+ if (group == null)
+ {
+ invitee.SendMessage(0x20, "", "MASSIVE ERROR: No tradegroup found!!!");
+ return;
+ }
+
+ Player inviter = (Player)invitee.GetZone().FindActorInArea(group.GetHost());
+
+ if (inviter != null)
+ inviter.SendGameMessage(GetActor(), 25038, 0x20); //Your trade request fails
+
+ DeleteTradeGroup(group.groupIndex);
+ }
+
public bool SendGroupInit(Session session, ulong groupId)
{
if (mContentGroups.ContainsKey(groupId))
@@ -870,6 +1024,11 @@ namespace FFXIVClassic_Map_Server
mContentGroups[groupId].SendInitWorkValues(session);
return true;
}
+ else if (mTradeGroups.ContainsKey(groupId))
+ {
+ mTradeGroups[groupId].SendInitWorkValues(session);
+ return true;
+ }
return false;
}
diff --git a/FFXIVClassic Map Server/actors/group/Relation.cs b/FFXIVClassic Map Server/actors/group/RelationGroup.cs
similarity index 94%
rename from FFXIVClassic Map Server/actors/group/Relation.cs
rename to FFXIVClassic Map Server/actors/group/RelationGroup.cs
index 600c8b9c..2d780498 100644
--- a/FFXIVClassic Map Server/actors/group/Relation.cs
+++ b/FFXIVClassic Map Server/actors/group/RelationGroup.cs
@@ -11,13 +11,13 @@ using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group
{
- class Relation : Group
+ class RelationGroup : Group
{
public RelationWork work = new RelationWork();
private uint charaOther;
private ulong topicGroup;
- public Relation(ulong groupIndex, uint host, uint other, uint command, ulong topicGroup) : base (groupIndex)
+ public RelationGroup(ulong groupIndex, uint host, uint other, uint command, ulong topicGroup) : base (groupIndex)
{
this.charaOther = other;
work._globalTemp.host = ((ulong)host << 32) | (0xc17909);
diff --git a/FFXIVClassic Map Server/actors/group/TradeGroup.cs b/FFXIVClassic Map Server/actors/group/TradeGroup.cs
new file mode 100644
index 00000000..49741307
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/TradeGroup.cs
@@ -0,0 +1,79 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.chara.npc;
+using FFXIVClassic_Map_Server.actors.group.Work;
+using FFXIVClassic_Map_Server.Actors;
+using FFXIVClassic_Map_Server.dataobjects;
+using FFXIVClassic_Map_Server.packets.send.group;
+using FFXIVClassic_Map_Server.packets.send.groups;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class TradeGroup : Group
+ {
+ public RelationWork work = new RelationWork();
+ private uint charaOther;
+ private ulong topicGroup;
+
+ public TradeGroup(ulong groupIndex, uint host, uint other)
+ : base(groupIndex)
+ {
+ this.charaOther = other;
+ work._globalTemp.host = ((ulong)host << 32) | (0xc17909);
+ work._globalTemp.variableCommand = 30001;
+ }
+
+ public uint GetHost()
+ {
+ return (uint)(((ulong)work._globalTemp.host >> 32) & 0xFFFFFFFF);
+ }
+
+ public uint GetOther()
+ {
+ return charaOther;
+ }
+
+ public override int GetMemberCount()
+ {
+ return 2;
+ }
+
+ public override uint GetTypeId()
+ {
+ return Group.TradeRelationGroup;
+ }
+
+ public ulong GetTopicGroupIndex()
+ {
+ return topicGroup;
+ }
+
+ public override List BuildMemberList(uint id)
+ {
+ List groupMembers = new List();
+
+ uint hostId = (uint)((work._globalTemp.host >> 32) & 0xFFFFFFFF);
+
+ groupMembers.Add(new GroupMember(hostId, -1, 0, false, Server.GetServer().GetSession(hostId) != null, Server.GetWorldManager().GetActorInWorld(hostId).customDisplayName));
+ groupMembers.Add(new GroupMember(charaOther, -1, 0, false, Server.GetServer().GetSession(charaOther) != null, Server.GetWorldManager().GetActorInWorld(charaOther).customDisplayName));
+ return groupMembers;
+ }
+
+ public override void SendInitWorkValues(Session session)
+ {
+ SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
+ groupWork.addProperty(this, "work._globalTemp.host");
+ groupWork.addProperty(this, "work._globalTemp.variableCommand");
+ groupWork.setTarget("/_init");
+
+ SubPacket test = groupWork.buildPacket(session.id);
+ test.DebugPrintSubPacket();
+ session.QueuePacket(test);
+ }
+
+ }
+}
diff --git a/data/scripts/commands/ConfirmTradeCommand.lua b/data/scripts/commands/ConfirmTradeCommand.lua
new file mode 100644
index 00000000..109f783c
--- /dev/null
+++ b/data/scripts/commands/ConfirmTradeCommand.lua
@@ -0,0 +1,20 @@
+--[[
+
+ConfirmTradeCommand Script
+
+Handles what happens when you accept/refuse a trade
+
+--]]
+
+function onEventStarted(player, actor, triggerName, groupType, result)
+
+ --Accept
+ if (result == 1) then
+ GetWorldManager():AcceptTrade(player);
+ --Refuse
+ elseif (result == 2) then
+ GetWorldManager():RefuseTrade(player);
+ end
+ player:EndEvent();
+
+end
\ No newline at end of file
diff --git a/data/scripts/commands/TradeOfferCancelCommand.lua b/data/scripts/commands/TradeOfferCancelCommand.lua
new file mode 100644
index 00000000..71edd609
--- /dev/null
+++ b/data/scripts/commands/TradeOfferCancelCommand.lua
@@ -0,0 +1,14 @@
+--[[
+
+TradeOfferCommand Script
+
+Handles what happens a player cancels a trade
+
+--]]
+
+function onEventStarted(player, actor, triggerName, commandId, result)
+
+ GetWorldManager():CancelTrade(player);
+ player:EndEvent();
+
+end
\ No newline at end of file
diff --git a/data/scripts/commands/TradeOfferCommand.lua b/data/scripts/commands/TradeOfferCommand.lua
new file mode 100644
index 00000000..8222d7d8
--- /dev/null
+++ b/data/scripts/commands/TradeOfferCommand.lua
@@ -0,0 +1,26 @@
+--[[
+
+TradeOfferCommand Script
+
+Handles what happens when you invite to trade
+
+--]]
+
+function onEventStarted(player, actor, triggerName, name, arg1, arg2, arg3, actorId)
+
+ local otherActor = nil;
+
+ if (name ~= nil) then
+ otherActor = player:GetZone():FindPCInZone(name);
+ elseif (actorId ~= nil) then
+ otherActor = player:GetZone():FindActorInArea(actorId);
+ end
+
+ if (otherActor ~= nil) then
+ GetWorldManager():CreateTradeGroup(player, otherActor);
+ else
+ end
+
+ player:EndEvent();
+
+end
\ No newline at end of file