Skip to content

Commit 84aa0a5

Browse files
committed
feat: Job Emblems
- Added support for job emblems - Created new personal quests to unlock emblems. - Added support for emblems using the menus at Renton. - Created new handlers and packets for the new menus.
1 parent c73ee85 commit 84aa0a5

106 files changed

Lines changed: 3648 additions & 237 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
CREATE TABLE ddon_job_emblem (
2+
"character_id" INTEGER NOT NULL,
3+
"job_id" INTEGER NOT NULL,
4+
"emblem_level" SMALLINT NOT NULL,
5+
"emblem_points_used" SMALLINT NOT NULL,
6+
"physical_attack" SMALLINT NOT NULL,
7+
"magick_attack" SMALLINT NOT NULL,
8+
"physical_defense" SMALLINT NOT NULL,
9+
"magick_defense" SMALLINT NOT NULL,
10+
"max_hp" SMALLINT NOT NULL,
11+
"max_stamina" SMALLINT NOT NULL,
12+
"healing_power" SMALLINT NOT NULL,
13+
"endurance" SMALLINT NOT NULL,
14+
"blow_power" SMALLINT NOT NULL,
15+
"chance_attack" SMALLINT NOT NULL,
16+
"exhaust_attack" SMALLINT NOT NULL,
17+
"knockout_power" SMALLINT NOT NULL,
18+
"fire_resist" SMALLINT NOT NULL,
19+
"ice_resist" SMALLINT NOT NULL,
20+
"thunder_resist" SMALLINT NOT NULL,
21+
"holy_resist" SMALLINT NOT NULL,
22+
"dark_resist" SMALLINT NOT NULL,
23+
CONSTRAINT pk_ddon_job_emblem PRIMARY KEY ("character_id", "job_id", "emblem_uid"),
24+
CONSTRAINT fk_ddon_job_emblem_character_id FOREIGN KEY ("character_id") REFERENCES "ddon_character" ("character_id") ON DELETE CASCADE
25+
);

Arrowgene.Ddon.Database/IDatabase.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,11 @@ bool UpdateCrest(
407407
string itemUId,
408408
uint slot,
409409
uint crestId,
410-
uint crestAmount
410+
uint crestAmount,
411+
DbConnection? ConnectionIn = null
411412
);
412413

413-
bool RemoveCrest(uint characterCommonId, string itemUId, uint slot);
414+
bool RemoveCrest(uint characterCommonId, string itemUId, uint slot, DbConnection? connectionIn = null);
414415
List<Crest> GetCrests(uint characterCommonId, string itemUId);
415416

416417
// Bitterblack Maze Progress
@@ -582,6 +583,10 @@ List<CDataJobOrderProgress> GetJobMasterActiveOrderProgress(uint characterId, Jo
582583
bool InsertSkillAugmentationReleasedElement(uint characterId, JobId jobId, uint releaseId, DbConnection? connectionIn = null);
583584
HashSet<uint> GetSkillAugmentationReleasedElements(uint characterId, JobId jobId, DbConnection? connectionIn = null);
584585

586+
public bool UpsertJobEmblemData(uint characterId, JobEmblem jobEmblem, DbConnection? connectionIn = null);
587+
public JobEmblem GetJobEmblemData(uint characterId, JobId jobId, DbConnection? connectionIn = null);
588+
public List<JobEmblem> GetAllJobEmblemData(uint characterId, DbConnection? connectionIn = null);
589+
585590
#region Pawn craft progress
586591

587592
bool ReplacePawnCraftProgress(CraftProgress craftProgress, DbConnection? connectionIn = null);

Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbCharacterCommon.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ private void QueryCharacterCommonData(DbConnection conn, CharacterCommon common)
157157

158158
using DbConnection connection3 = OpenNewConnection();
159159
item.AddStatusParamList = GetEquipmentLimitBreakRecord(item.UId, connection3);
160+
item.EquipStatParamList.Add(new CDataEquipStatParam() { EffectID = (byte) EquipStatId.MaxHp, EffectValue = 50 });
160161

161162
common.EquipmentTemplate.SetEquipItem(item, job, equipType, equipSlot);
162163
}

Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbCrest.cs

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,39 +49,32 @@ public override bool InsertCrest(uint characterCommonId, string itemUId, uint sl
4949
}
5050
}
5151

52-
public override bool UpdateCrest(uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount)
52+
public override bool UpdateCrest(uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount, DbConnection? connectionIn = null)
5353
{
54-
using DbConnection connection = OpenNewConnection();
55-
return UpdateCrest(connection, characterCommonId, itemUId, slot, crestId, crestAmount);
56-
}
57-
58-
public bool UpdateCrest(DbConnection connection, uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount)
59-
{
60-
return ExecuteNonQuery(connection, SqlUpdateCrestData, command =>
54+
return ExecuteQuerySafe(connectionIn, connection =>
6155
{
62-
AddParameter(command, "character_common_id", characterCommonId);
63-
AddParameter(command, "item_uid", itemUId);
64-
AddParameter(command, "slot", slot);
65-
AddParameter(command, "crest_id", crestId);
66-
AddParameter(command, "crest_amount", crestAmount);
67-
}) == 1;
68-
;
69-
}
70-
71-
public override bool RemoveCrest(uint characterCommonId, string itemUId, uint slot)
72-
{
73-
using DbConnection connection = OpenNewConnection();
74-
return RemoveCrest(connection, characterCommonId, itemUId, slot);
56+
return ExecuteNonQuery(connection, SqlUpdateCrestData, command =>
57+
{
58+
AddParameter(command, "character_common_id", characterCommonId);
59+
AddParameter(command, "item_uid", itemUId);
60+
AddParameter(command, "slot", slot);
61+
AddParameter(command, "crest_id", crestId);
62+
AddParameter(command, "crest_amount", crestAmount);
63+
}) == 1;
64+
});
7565
}
7666

77-
public bool RemoveCrest(DbConnection connection, uint characterCommonId, string itemUId, uint slot)
67+
public override bool RemoveCrest(uint characterCommonId, string itemUId, uint slot, DbConnection? connectionIn = null)
7868
{
79-
return ExecuteNonQuery(connection, SqlDeleteCrestData, command =>
69+
return ExecuteQuerySafe(connectionIn, connection =>
8070
{
81-
AddParameter(command, "character_common_id", characterCommonId);
82-
AddParameter(command, "item_uid", itemUId);
83-
AddParameter(command, "slot", slot);
84-
}) == 1;
71+
return ExecuteNonQuery(connection, SqlDeleteCrestData, command =>
72+
{
73+
AddParameter(command, "character_common_id", characterCommonId);
74+
AddParameter(command, "item_uid", itemUId);
75+
AddParameter(command, "slot", slot);
76+
}) == 1;
77+
});
8578
}
8679

8780
public override List<Crest> GetCrests(uint characterCommonId, string itemUId)
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using Arrowgene.Ddon.Shared.Model;
2+
using System.Collections.Generic;
3+
using System.Data.Common;
4+
5+
namespace Arrowgene.Ddon.Database.Sql.Core;
6+
7+
public partial class DdonSqlDb : SqlDb
8+
{
9+
/* ddon_job_emblem */
10+
protected static readonly string[] JobEmblemFields = new[]
11+
{
12+
"character_id", "job_id", "emblem_level", "emblem_points_used",
13+
"physical_attack", "magick_attack", "physical_defense", "magick_defense",
14+
"max_hp", "max_stamina", "healing_power", "endurance", "blow_power", "chance_attack", "exhaust_attack",
15+
"knockout_power", "fire_resist", "ice_resist", "thunder_resist", "holy_resist", "dark_resist"
16+
};
17+
18+
private readonly string SqlUpsertJobEmblemData = $"""
19+
INSERT INTO ddon_job_emblem ({BuildQueryField(JobEmblemFields)})
20+
VALUES ({BuildQueryInsert(JobEmblemFields)})
21+
ON CONFLICT (character_id, job_id)
22+
DO UPDATE SET {BuildQueryUpdate(JobEmblemFields)};
23+
""";
24+
25+
private readonly string SqlSelectAllJobEmblemData =
26+
$"SELECT {BuildQueryField(JobEmblemFields)} FROM \"ddon_job_emblem\" WHERE \"character_id\"=@character_id;";
27+
28+
private readonly string SqlSelectJobEmblemData =
29+
$"SELECT {BuildQueryField(JobEmblemFields)} FROM \"ddon_job_emblem\" WHERE \"character_id\"=@character_id AND \"job_id\"=@job_id;";
30+
31+
public override bool UpsertJobEmblemData(uint characterId, JobEmblem jobEmblem, DbConnection? connectionIn = null)
32+
{
33+
return ExecuteQuerySafe(connectionIn, connection =>
34+
{
35+
return ExecuteNonQuery(connection, SqlUpsertJobEmblemData, command =>
36+
{
37+
AddParameter(command, "character_id", characterId);
38+
AddParameter(command, "job_id", (byte)jobEmblem.JobId);
39+
AddParameter(command, "emblem_level", jobEmblem.EmblemLevel);
40+
AddParameter(command, "emblem_points_used", jobEmblem.EmblemPointsUsed);
41+
AddParameter(command, "physical_attack", jobEmblem.StatLevels[EquipStatId.PhysicalAttack]);
42+
AddParameter(command, "magick_attack", jobEmblem.StatLevels[EquipStatId.MagickAttack]);
43+
AddParameter(command, "physical_defense", jobEmblem.StatLevels[EquipStatId.PhysicalDefense]);
44+
AddParameter(command, "magick_defense", jobEmblem.StatLevels[EquipStatId.MagickDefense]);
45+
AddParameter(command, "max_hp", jobEmblem.StatLevels[EquipStatId.MaxHp]);
46+
AddParameter(command, "max_stamina", jobEmblem.StatLevels[EquipStatId.MaxStamina]);
47+
AddParameter(command, "healing_power", jobEmblem.StatLevels[EquipStatId.HealingPower]);
48+
AddParameter(command, "endurance", jobEmblem.StatLevels[EquipStatId.Endurance]);
49+
AddParameter(command, "blow_power", jobEmblem.StatLevels[EquipStatId.BlowPower]);
50+
AddParameter(command, "chance_attack", jobEmblem.StatLevels[EquipStatId.ChanceAttack]);
51+
AddParameter(command, "exhaust_attack", jobEmblem.StatLevels[EquipStatId.ExhaustAttack]);
52+
AddParameter(command, "knockout_power", jobEmblem.StatLevels[EquipStatId.KnockoutPower]);
53+
AddParameter(command, "fire_resist", jobEmblem.StatLevels[EquipStatId.FireResist]);
54+
AddParameter(command, "ice_resist", jobEmblem.StatLevels[EquipStatId.IceResist]);
55+
AddParameter(command, "thunder_resist", jobEmblem.StatLevels[EquipStatId.ThunderResist]);
56+
AddParameter(command, "holy_resist", jobEmblem.StatLevels[EquipStatId.HolyResist]);
57+
AddParameter(command, "dark_resist", jobEmblem.StatLevels[EquipStatId.DarkResist]);
58+
}) == 1;
59+
});
60+
}
61+
62+
public override List<JobEmblem> GetAllJobEmblemData(uint characterId, DbConnection? connectionIn = null)
63+
{
64+
List<JobEmblem> results = new();
65+
ExecuteQuerySafe(connectionIn, connection =>
66+
{
67+
ExecuteReader(connection, SqlSelectAllJobEmblemData, command =>
68+
{
69+
AddParameter(command, "character_id", characterId);
70+
},
71+
reader =>
72+
{
73+
while (reader.Read())
74+
{
75+
results.Add(ReadEmblemData(reader));
76+
}
77+
});
78+
});
79+
return results;
80+
}
81+
82+
public override JobEmblem GetJobEmblemData(uint characterId, JobId jobId, DbConnection? connectionIn = null)
83+
{
84+
JobEmblem result = null;
85+
ExecuteQuerySafe(connectionIn, connection =>
86+
{
87+
ExecuteReader(connection, SqlSelectJobEmblemData, command =>
88+
{
89+
AddParameter(command, "character_id", characterId);
90+
AddParameter(command, "job_id", (byte)jobId);
91+
}, reader =>
92+
{
93+
if (reader.Read())
94+
{
95+
result = ReadEmblemData(reader);
96+
}
97+
});
98+
});
99+
return result;
100+
}
101+
102+
private JobEmblem ReadEmblemData(DbDataReader reader)
103+
{
104+
var result = new JobEmblem
105+
{
106+
JobId = (JobId)GetByte(reader, "job_id"),
107+
EmblemLevel = GetByte(reader, "emblem_level"),
108+
EmblemPointsUsed = GetUInt16(reader, "emblem_points_used"),
109+
};
110+
111+
result.StatLevels[EquipStatId.PhysicalAttack] = GetByte(reader, "physical_attack");
112+
result.StatLevels[EquipStatId.PhysicalDefense] = GetByte(reader, "physical_defense");
113+
result.StatLevels[EquipStatId.MagickAttack] = GetByte(reader, "magick_attack");
114+
result.StatLevels[EquipStatId.MagickDefense] = GetByte(reader, "magick_defense");
115+
result.StatLevels[EquipStatId.MaxHp] = GetByte(reader, "max_hp");
116+
result.StatLevels[EquipStatId.MaxStamina] = GetByte(reader, "max_stamina");
117+
result.StatLevels[EquipStatId.HealingPower] = GetByte(reader, "healing_power");
118+
result.StatLevels[EquipStatId.Endurance] = GetByte(reader, "endurance");
119+
result.StatLevels[EquipStatId.BlowPower] = GetByte(reader, "blow_power");
120+
result.StatLevels[EquipStatId.ChanceAttack] = GetByte(reader, "chance_attack");
121+
result.StatLevels[EquipStatId.ExhaustAttack] = GetByte(reader, "exhaust_attack");
122+
result.StatLevels[EquipStatId.KnockoutPower] = GetByte(reader, "knockout_power");
123+
result.StatLevels[EquipStatId.FireResist] = GetByte(reader, "fire_resist");
124+
result.StatLevels[EquipStatId.IceResist] = GetByte(reader, "ice_resist");
125+
result.StatLevels[EquipStatId.ThunderResist] = GetByte(reader, "thunder_resist");
126+
result.StatLevels[EquipStatId.HolyResist] = GetByte(reader, "holy_resist");
127+
result.StatLevels[EquipStatId.DarkResist] = GetByte(reader, "dark_resist");
128+
129+
return result;
130+
}
131+
}

Arrowgene.Ddon.Database/Sql/SqlDb.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,8 @@ public abstract int UpdateContact(uint requestingCharacterId, uint requestedChar
481481
public abstract bool InsertCharacterStampData(uint id, CharacterStampBonus stampData);
482482
public abstract bool UpdateCharacterStampData(uint id, CharacterStampBonus stampData);
483483
public abstract bool InsertCrest(uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount, DbConnection? connectionIn = null);
484-
public abstract bool UpdateCrest(uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount);
485-
public abstract bool RemoveCrest(uint characterCommonId, string itemUId, uint slot);
484+
public abstract bool UpdateCrest(uint characterCommonId, string itemUId, uint slot, uint crestId, uint crestAmount, DbConnection? ConnectionIn = null);
485+
public abstract bool RemoveCrest(uint characterCommonId, string itemUId, uint slot, DbConnection? connectionIn = null);
486486
public abstract List<Crest> GetCrests(uint characterCommonId, string itemUId);
487487
public abstract bool InsertBBMCharacterId(uint characterId, uint bbmCharacterId);
488488
public abstract uint SelectBBMCharacterId(uint characterId, DbConnection? connectionIn = null);
@@ -608,6 +608,10 @@ public abstract List<CDataJobOrderProgress> GetJobMasterActiveOrderProgress(uint
608608
public abstract bool InsertSkillAugmentationReleasedElement(uint characterId, JobId jobId, uint releaseId, DbConnection? connectionIn = null);
609609
public abstract HashSet<uint> GetSkillAugmentationReleasedElements(uint characterId, JobId jobId, DbConnection? connectionIn = null);
610610

611+
public abstract bool UpsertJobEmblemData(uint characterId, JobEmblem jobEmblem, DbConnection? connectionIn = null);
612+
public abstract JobEmblem GetJobEmblemData(uint characterId, JobId jobId, DbConnection? connectionIn = null);
613+
public abstract List<JobEmblem> GetAllJobEmblemData(uint characterId, DbConnection? connectionIn = null);
614+
611615
protected virtual DbCommand Command(string query, DbConnection connection)
612616
{
613617
throw new NotImplementedException("This is driver-dependent and must be implemented.");

Arrowgene.Ddon.GameServer/Characters/CharacterManager.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public Character SelectCharacter(uint characterId, bool fetchPawns = true, DbCon
5555
}
5656

5757
character.Server = Server.AssetRepository.ServerList.Where(server => server.Id == Server.Id).Single().ToCDataGameServerListInfo();
58+
59+
// Apply Emblem stats before setting up character equipment
60+
character.JobEmblems = Server.JobEmblemManager.InitializeEmblemData(character, connectionIn);
5861
character.Equipment = character.Storage.GetCharacterEquipment();
5962

6063
character.ContentsReleased = GetContentsReleased(character, connectionIn);
@@ -80,7 +83,6 @@ public Character SelectCharacter(uint characterId, bool fetchPawns = true, DbCon
8083
foreach (var jobId in Enum.GetValues(typeof(JobId)).Cast<JobId>())
8184
{
8285
character.JobMasterReleasedElements[jobId] = Server.Database.GetJobMasterReleasedElements(character.CharacterId, jobId, connectionIn);
83-
8486
character.JobMasterActiveOrders[jobId] = Server.JobMasterManager.GetJobMasterActiveOrders(character, jobId, connectionIn);
8587
}
8688

@@ -381,19 +383,19 @@ public void UpdateCharacterExtendedParams(CharacterCommon characterCommon, bool
381383
* The stat boosts rewarded for this mechanism rewards both stats for all jobs and stats for
382384
* a specific job only. We abuse JobId.None to store the stats for all jobs.
383385
*/
384-
var extendedParams = characterCommon.ExtendedJobParams;
386+
var extendedJobParams = characterCommon.ExtendedJobParams;
385387
JobId jobId = characterCommon.ActiveCharacterJobData.Job;
386388
if (characterCommon is Pawn)
387389
{
388-
extendedParams = ownerCharacter.ExtendedJobParams;
390+
extendedJobParams = ownerCharacter.ExtendedJobParams;
389391
}
390392

391-
characterCommon.StatusInfo.GainAttack += (uint)(extendedParams[JobId.None].Attack + extendedParams[jobId].Attack);
392-
characterCommon.StatusInfo.GainDefense += (uint)(extendedParams[JobId.None].Defence + extendedParams[jobId].Defence);
393-
characterCommon.StatusInfo.GainMagicAttack += (uint)(extendedParams[JobId.None].MagicAttack + extendedParams[jobId].MagicAttack);
394-
characterCommon.StatusInfo.GainMagicDefense += (uint)(extendedParams[JobId.None].MagicDefence + extendedParams[jobId].MagicDefence);
395-
characterCommon.StatusInfo.GainStamina += (uint)(extendedParams[JobId.None].StaminaMax + extendedParams[jobId].StaminaMax);
396-
characterCommon.StatusInfo.GainHP += (uint)(extendedParams[JobId.None].HpMax + extendedParams[jobId].HpMax);
393+
characterCommon.StatusInfo.GainAttack += (uint)(extendedJobParams[JobId.None].Attack + extendedJobParams[jobId].Attack);
394+
characterCommon.StatusInfo.GainDefense += (uint)(extendedJobParams[JobId.None].Defence + extendedJobParams[jobId].Defence);
395+
characterCommon.StatusInfo.GainMagicAttack += (uint)(extendedJobParams[JobId.None].MagicAttack + extendedJobParams[jobId].MagicAttack);
396+
characterCommon.StatusInfo.GainMagicDefense += (uint)(extendedJobParams[JobId.None].MagicDefence + extendedJobParams[jobId].MagicDefence);
397+
characterCommon.StatusInfo.GainStamina += (uint)(extendedJobParams[JobId.None].StaminaMax + extendedJobParams[jobId].StaminaMax);
398+
characterCommon.StatusInfo.GainHP += (uint)(extendedJobParams[JobId.None].HpMax + extendedJobParams[jobId].HpMax);
397399

398400
/**
399401
* Seems when the game first loads, the game wants MaxHP to always be 760
@@ -471,7 +473,7 @@ private PacketQueue NotifyClientOfCharacterStatus(GameClient client, CharacterCo
471473
if (characterCommon is Character)
472474
{
473475
S2CContextGetLobbyPlayerContextNtc ntc1 = new S2CContextGetLobbyPlayerContextNtc();
474-
GameStructure.S2CContextGetLobbyPlayerContextNtc(ntc1, (Character) characterCommon);
476+
GameStructure.S2CContextGetLobbyPlayerContextNtc(Server, ntc1, (Character) characterCommon);
475477

476478
S2CExtendEquipSlotNtc ntc2 = new S2CExtendEquipSlotNtc()
477479
{

0 commit comments

Comments
 (0)