Skip to content
7 changes: 5 additions & 2 deletions doc/bt/CZ_PARTY_PROP_CHANGE.bt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@
#include "inc/common.bt"

ClientHeaderFixed header;
byte b1;
getProperties(17*8);

PartyType type;
int propertyId;
int i1;
char propertyValue[64];
12 changes: 6 additions & 6 deletions doc/bt/ZC_ENTER_PC.bt
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@
// - i174236: b3 was added
// - i197611: b3 was removed
// - i373230: i6 was added
// - i381165: b4 was added
// - changed from s2 (short) to 2 bytes
//------------------------------------------------

#include "inc/common.bt"

ServerHeaderFixed header;

int handle;
float x;
float y;
float z;
float dcos;
float dsin;
position pos;
direction dir;
short s1;
int64 socialInfoId;
byte pose; // ?
Expand All @@ -42,7 +41,8 @@ int i6;
int stamina;
int maxStamina;
byte b1;
short s2;
byte b0;
byte isSitting;
int titleAchievementId;
int i3;
byte b2;
Expand Down
7 changes: 4 additions & 3 deletions doc/bt/ZC_PARTY_INFO.bt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//------------------------------------------------
//--- 010 Editor v8.0 Binary Template
//
// File: ZC_PARTY_INFO
// Authors: Tachiorz
// File: ZC_PARTY_INFO.bt
// Authors: Tachiorz, Salman T. Khan
// Version: i11XXX
// Purpose:
// Category:
Expand All @@ -15,7 +15,8 @@

ServerHeaderDynamic header;

short partyType; // 0: normal, 1: guild
PartyType partyType; // 0: normal, 1: guild
byte b1;

// PARTY_INFO
FILETIME creationTime;
Expand Down
11 changes: 6 additions & 5 deletions doc/bt/inc/Party.bt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ typedef struct
int64 l1;
int i11;
int i0;
int i1;
int mapId; // Might be offline if set to 0?
int handle;
char teamName1[64];
char characterName[64];
Expand All @@ -38,10 +38,11 @@ typedef struct
short baseJob1;
ushort s10;
int jobLevel;
short s5;
int i5;
byte bin[18];
int mapId; // removed s12 and merged, it was a 0
short gender;
short hair;
int i12;
byte bin[16];
int serverGroup; // removed s12 and merged, it was a 0
int level;
byte b1;
byte b2;
Expand Down
16 changes: 16 additions & 0 deletions sql/updates/update_2025-01-13_1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Add partyId column to characters table for party persistence
ALTER TABLE `characters` ADD COLUMN `partyId` BIGINT NOT NULL DEFAULT '0' AFTER `usedStat`;

-- Create party table for storing party information
CREATE TABLE IF NOT EXISTS `party` (
`partyId` bigint(20) NOT NULL AUTO_INCREMENT,
`leaderId` bigint(20) NOT NULL,
`name` varchar(64) NOT NULL,
`note` varchar(64) NOT NULL,
`dateCreated` DATETIME DEFAULT CURRENT_TIMESTAMP,
`questSharing` tinyint(1) DEFAULT '1',
`expDistribution` tinyint(1) DEFAULT '1',
`itemDistribution` tinyint(1) DEFAULT '1',
PRIMARY KEY (`partyId`),
KEY `leaderId` (`leaderId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
23 changes: 23 additions & 0 deletions src/Shared/Configuration/Files/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ public class WorldConfFile : ConfFile
// misc.conf
public bool ResurrectCityOption { get; protected set; }

// party.conf
public float PartyExpMultiplier2 { get; protected set; }
public float PartyExpMultiplier3 { get; protected set; }
public float PartyExpMultiplier4 { get; protected set; }
public float PartyExpMultiplier5Plus { get; protected set; }
public int PartyLevelPenaltyThreshold1 { get; protected set; }
public float PartyLevelPenalty1 { get; protected set; }
public int PartyLevelPenaltyThreshold2 { get; protected set; }
public float PartyLevelPenalty2 { get; protected set; }
public int PartyLevelPenaltyThreshold3 { get; protected set; }
public float PartyLevelPenalty3 { get; protected set; }

// quests.conf
public bool DisplayQuestObjectives { get; protected set; }

Expand Down Expand Up @@ -140,6 +152,17 @@ public void Load(string filePath)

this.ResurrectCityOption = this.GetBool("resurrect_city_option", true);

this.PartyExpMultiplier2 = this.GetFloat("party_exp_multiplier_2", 1.2f);
this.PartyExpMultiplier3 = this.GetFloat("party_exp_multiplier_3", 1.5f);
this.PartyExpMultiplier4 = this.GetFloat("party_exp_multiplier_4", 1.8f);
this.PartyExpMultiplier5Plus = this.GetFloat("party_exp_multiplier_5plus", 2.2f);
this.PartyLevelPenaltyThreshold1 = this.GetInt("party_level_penalty_threshold_1", 10);
this.PartyLevelPenalty1 = this.GetFloat("party_level_penalty_1", 0.7f);
this.PartyLevelPenaltyThreshold2 = this.GetInt("party_level_penalty_threshold_2", 15);
this.PartyLevelPenalty2 = this.GetFloat("party_level_penalty_2", 0.4f);
this.PartyLevelPenaltyThreshold3 = this.GetInt("party_level_penalty_threshold_3", 20);
this.PartyLevelPenalty3 = this.GetFloat("party_level_penalty_3", 0.0f);

this.DisplayQuestObjectives = this.GetBool("display_quest_objectives", true);

this.DisableSDR = this.GetBool("disable_sdr", false);
Expand Down
14 changes: 14 additions & 0 deletions src/Shared/Game/Const/GroupType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Melia.Shared.Game.Const
{
public enum GroupType
{
Party = 0,
Guild = 1,
}
}
3 changes: 3 additions & 0 deletions src/Shared/Game/Const/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ public static class AddonMessage

public const string ENABLE_PCBANG_SHOP = "ENABLE_PCBANG_SHOP";

public const string PARTY_JOIN = "PARTY_JOIN";
public const string PARTY_UPDATE = "PARTY_UPDATE";
public const string PARTY_INVITE_CANCEL = "PARTY_INVITE_CANCEL";
public const string SUCCESS_UPDATE_PARTY_INFO = "SUCCESS_UPDATE_PARTY_INFO";
public const string UPDATE_GUILD_MILEAGE = "UPDATE_GUILD_MILEAGE";
public const string UPDATE_ATTENDANCE_REWARD = "UPDATE_ATTENDANCE_REWARD";

Expand Down
50 changes: 50 additions & 0 deletions src/Shared/Game/Const/RelationType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Text.RegularExpressions;

namespace Melia.Shared.Game.Const
{
/// <summary>
/// Used to specify the type of a monster.
/// </summary>
public enum RelationType : byte
{
/// <summary>
/// Party/Guild
/// </summary>
Friendly = 0,

/// <summary>
/// An aggressive monster.
/// </summary>
Enemy = 1,

/// <summary>
/// An NPC or item.
/// </summary>
Neutral = 2,

/// <summary>
/// A party member
/// </summary>
Party = 3,

/// <summary>
/// A guild member
/// </summary>
Guild = 4,

/// <summary>
/// Is a player
/// </summary>
Character = 5,

/// <summary>
/// Is a monster
/// </summary>
Monster = 6,

/// <summary>
/// All relations
/// </summary>
All = 127,
}
}
8 changes: 8 additions & 0 deletions src/Shared/Network/NormalOp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,20 @@ public static class Zone
public const int PlayTextEffect = 0xE3;
public const int Unknown_E4 = 0xE7;
public const int Unknown_EF = 0xF2;
public const int PartyMemberData = 0xF4;
public const int PartyLeaderChange = 0xF6;
public const int PartyNameChange = 0xF7;
public const int PartyInvite = 0xF8;
public const int PartyPropertyChange = 0xF9;
public const int PartyMemberPropertyChange = 0xFA;
public const int ChannelTraffic = 0x12D;
public const int SetGreetingMessage = 0x136;
public const int ShowParty = 0x13C;
public const int Unk13E = 0x13E;
public const int SetSessionKey = 0x14F;
public const int ItemDrop = 0x152;
public const int NGSCallback = 0x170;
public const int MemberMapStatusUpdate = 0x17A;
public const int HeadgearVisibilityUpdate = 0x17C;
public const int UpdateSkillUI = 0x189;
public const int AdventureBook = 0x197;
Expand Down
5 changes: 5 additions & 0 deletions src/Shared/ObjectProperties/PropertyObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ public interface IPropertyObject : IPropertyHolder

public static class ObjectIdRanges
{
public const long Account = 0x0000000000000000;
public const long Characters = 0x0100000000000000;
public const long SocialUser = 0x0200000000000000;
public const long Items = 0x0500000000000000;
public const long Skills = 0x0600000000000000;
public const long Abilities = 0x0700000000000000;
public const long SessionObjects = 0x0A00000000000000;
public const long Quests = 0x0B00000000000000;
public const long Companions = 0x0C00000000000000;
public const long Party = 0x0D00000000000000;
public const long Guild = 0x0E00000000000000;
public const long Assisters = 0x0F00000000000000;

// Old stuff for referecence:

Expand Down
22 changes: 22 additions & 0 deletions src/Shared/Util/DateTimeUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

namespace Melia.Shared.Util
{
public static class DateTimeUtils
{
/// <summary>
/// Returns date time in a year(yyyy), month(MM), day of week(0-6),
/// date (dd), hour (HH), minutes (mm) and seconds (ss)
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static string ToPropertyDateTimeString(this DateTime dateTime)
{
var yearMonth = dateTime.ToString("yyyyMM");
var date = dateTime.ToString("dd");
var time = dateTime.ToString("HHmmss");

return yearMonth + $"{(int)dateTime.DayOfWeek}" + date + time;
}
}
}
35 changes: 34 additions & 1 deletion src/SocialServer/Commands/ChatCommands.Handlers.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using Melia.Social.Database;
using Melia.Social.Network;
using Melia.Social.World;
Expand All @@ -19,6 +19,7 @@ public ChatCommands()
{
this.Add("w", "<teamName> <message>", "", this.HandleWhisper);
this.Add("f", "<chatId> <message>", "", this.HandleChatRoomChat);
this.Add("p", "<message>", "", this.HandlePartyChat);
}

/// <summary>
Expand Down Expand Up @@ -99,5 +100,37 @@ private CommandResult HandleChatRoomChat(SocialUser user, string message, string

return CommandResult.Okay;
}

/// <summary>
/// Request to send a party chat message.
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <param name="command"></param>
/// <param name="args"></param>
/// <returns></returns>
private CommandResult HandlePartyChat(SocialUser user, string message, string command, Arguments args)
{
if (args.Count < 1)
{
return CommandResult.Okay;
}

var text = message.Substring(message.IndexOf(" "));

if (string.IsNullOrEmpty(text))
return CommandResult.Okay;


if (!SocialServer.Instance.ChatManager.TryGetChatRoom(user.Character.PartyId, out var chatRoom))
{
chatRoom = SocialServer.Instance.ChatManager.CreateChatRoom(user, user.Character.PartyId, ChatRoomType.Friends);
}

var chatMessage = new ChatMessage(user, text, ChatMessageType.Party);
chatRoom.AddMessage(chatMessage);

return CommandResult.Okay;
}
}
}
5 changes: 5 additions & 0 deletions src/SocialServer/Database/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public class Character
/// </summary>
public int ChannelId { get; set; }

/// <summary>
/// Gets or sets the character's party id.
/// </summary>
public long PartyId { get; set; }

/// <summary>
/// Resets select properties that will make the character appear offline
/// when included in a friend list refresh.
Expand Down
Loading