Skip to content

Commit 434463a

Browse files
Merge pull request #203 from UchuServer/enhancement/factions
Enhancement/factions
2 parents 7d5a370 + 28d7201 commit 434463a

18 files changed

+462
-189
lines changed

Uchu.World/Handlers/Commands/CharacterCommandHandler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,9 +1061,10 @@ public async Task<string> Complete(string[] arguments, Player player)
10611061
[CommandHandler(Signature = "clear", Help = "Clears your inventory", GameMasterLevel = GameMasterLevel.Admin)]
10621062
public async Task<string> Clear(string[] arguments, Player player)
10631063
{
1064-
foreach (var item in player.GetComponent<InventoryManagerComponent>()[InventoryType.Items].Items)
1064+
var inventory = player.GetComponent<InventoryManagerComponent>();
1065+
foreach (var item in inventory[InventoryType.Items].Items)
10651066
{
1066-
await item.DecrementCountAsync(item.Count);
1067+
await inventory.RemoveItemAsync(item);
10671068
}
10681069

10691070
return "Cleared inventory";

Uchu.World/Handlers/GameMessages/GeneralHandler.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,51 @@
33
using Microsoft.EntityFrameworkCore;
44
using Uchu.Core;
55
using Uchu.Core.Client;
6+
using Uchu.Core.Resources;
67
using Uchu.World.Client;
78

89
namespace Uchu.World.Handlers.GameMessages
910
{
1011
public class GeneralHandler : HandlerGroup
1112
{
13+
14+
/// <summary>
15+
/// For the faction initial missions this sets their state from started to ready to complete on an interaction
16+
/// </summary>
17+
/// <param name="gameObject">The game object to interact with</param>
18+
/// <param name="missions">The missions inventory of a player</param>
19+
private static async Task HandleFactionVendorInteraction(GameObject gameObject, MissionInventoryComponent missions)
20+
{
21+
// For some reason the targets of faction missions are different game objects than the one you interact with
22+
var targetLot = (int) gameObject.Lot switch
23+
{
24+
Lot.SentinelFactionVendor => Lot.SentinelFactionVendorProxy,
25+
Lot.ParadoxFactionVendor => Lot.ParadoxFactionVendorProxy,
26+
Lot.AssemblyFactionVendor => Lot.AssemblyFactionVendorProxy,
27+
Lot.VentureFactionVendor => Lot.VentureFactionVendorProxy,
28+
_ => default
29+
};
30+
31+
if (targetLot != default)
32+
await missions.GoToNpcAsync(targetLot);
33+
}
34+
1235
[PacketHandler]
1336
public async Task RequestUseHandler(RequestUseMessage message, Player player)
1437
{
1538
Logger.Information($"{player} interacted with {message.TargetObject}");
1639

1740
var inventory = player.GetComponent<MissionInventoryComponent>();
18-
1941
await inventory.GoToNpcAsync(
2042
message.TargetObject.Lot
2143
);
44+
45+
// Handle interactions with the faction vendors
46+
await HandleFactionVendorInteraction(message.TargetObject, inventory);
2247

2348
if (message.IsMultiInteract)
2449
{
25-
//
2650
// Multi-interact is mission
27-
//
28-
2951
if (message.MultiInteractType == 0) // Mission Component
3052
{
3153
player.GetComponent<MissionInventoryComponent>().MessageOfferMission(
@@ -36,14 +58,12 @@ await inventory.GoToNpcAsync(
3658
else if (message.MultiInteractType == 1) // Any other case
3759
{
3860
await message.TargetObject.OnInteract.InvokeAsync(player);
39-
4061
await inventory.InteractAsync(message.TargetObject.Lot);
4162
}
4263
}
4364
else if (message.TargetObject != default)
4465
{
4566
await message.TargetObject.OnInteract.InvokeAsync(player);
46-
4767
await inventory.InteractAsync(message.TargetObject.Lot);
4868
}
4969
}

Uchu.World/Handlers/WorldInitializationHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ private static InventoryNode InventoryNode(Character character)
259259
ItemContainerNode(character, InventoryType.Items),
260260
ItemContainerNode(character, InventoryType.Bricks),
261261
ItemContainerNode(character, InventoryType.Models),
262-
ItemContainerNode(character, InventoryType.Behaviors)
262+
ItemContainerNode(character, InventoryType.Behaviors),
263+
ItemContainerNode(character, InventoryType.Hidden)
263264
}
264265
};
265266
}

Uchu.World/Objects/Components/Player/InventoryManagerComponent.cs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ await inventory.LoadItems(
8888

8989
_inventories.Add(inventoryType, inventory);
9090
}
91+
92+
// Finally load all the sub items
93+
if (this[InventoryType.Hidden] is {} hiddenInventory)
94+
await hiddenInventory.LoadItems(playerCharacter.Items.Where(i => i.ParentId != ObjectId.Invalid
95+
&& (InventoryType) i.InventoryType == InventoryType.Hidden));
9196
});
9297

9398
Listen(OnDestroyed, () =>
@@ -106,11 +111,7 @@ await inventory.LoadItems(
106111
public async Task SaveAsync(UchuContext context)
107112
{
108113
var itemsToSave = Items;
109-
110-
// If the inventory is empty something went terribly wrong, do NOT save
111-
if (itemsToSave.Length == 0)
112-
return;
113-
114+
114115
var character = await context.Characters.Where(c => c.Id == GameObject.Id)
115116
.Include(c => c.Items)
116117
.FirstAsync();
@@ -193,6 +194,19 @@ public Item FindItem(Lot lot, InventoryType inventoryType)
193194
return _inventories[inventoryType].Items.FirstOrDefault(i => i.Lot == lot);
194195
}
195196

197+
/// <summary>
198+
/// Finds and returns the first item of a certain lot in a certain inventory given that the provided argument
199+
/// item is its parent
200+
/// </summary>
201+
/// <param name="lot">The lot of the item to look for</param>
202+
/// <param name="inventoryType">The inventory type to look in for the item</param>
203+
/// <param name="rootItem">The root item that this item needs to belong to</param>
204+
/// <returns>The item retrieved from the given inventory</returns>
205+
public Item FindItem(Lot lot, InventoryType inventoryType, Item rootItem)
206+
{
207+
return _inventories[inventoryType].Items.FirstOrDefault(i => i.Lot == lot && i.RootItem?.Id == rootItem.Id);
208+
}
209+
196210
/// <summary>
197211
/// Finds an item by looking for the provided lot in the given inventory type and ensuring that said item has a
198212
/// count of at least minimumCount
@@ -223,14 +237,7 @@ public Item[] FindItems(Lot lot) => _inventories.Values.SelectMany(
223237
/// <returns>List of all found items</returns>
224238
public Item[] FindItems(Lot lot, InventoryType inventoryType) =>
225239
_inventories[inventoryType].Items.Where(i => i.Lot == lot).ToArray();
226-
227-
/// <summary>
228-
/// If this is a sub item, it returns the root item of this item. If this item is a root item, it returns itself.
229-
/// </summary>
230-
/// <param name="item">The item to find the root item for</param>
231-
/// <returns>The root item of this item if it is a sub item, the same item otherwise</returns>
232-
public Item GetRootItem(Item item) => Items.FirstOrDefault(i => i.Id == item.RootItem?.Id) ?? item;
233-
240+
234241
#endregion finditem
235242

236243
/// <summary>
@@ -297,19 +304,26 @@ private static async Task<ItemComponent> GetItemComponentForLotAysnc(Lot lot)
297304

298305
return itemComponent;
299306
}
300-
307+
301308
/// <summary>
302309
/// Adds a new lot to the inventory. The lot will automatically instantiated as the required amount of items
303310
/// based on the provided count and the stack size of that item.
304311
/// </summary>
312+
/// <remarks>
313+
/// The returning list may be empty if it was possible to distribute over already existing stacks
314+
/// </remarks>
305315
/// <param name="lot">The lot to add to the inventory</param>
306316
/// <param name="count">The count of the lot we want to add to the inventory</param>
307-
/// <param name="inventoryType">Optional explicit inventory type to add this lot to, if not provided this will be
308-
/// implicitly retrieved from the item lot, generally used for vendor buy back</param>
309317
/// <param name="settings">Optional <c>LegoDataDictionary</c> to instantiate the item with</param>
310-
public async Task AddLotAsync(Lot lot, uint count, LegoDataDictionary settings = default,
311-
InventoryType inventoryType = default)
318+
/// <param name="inventoryType">Optional explicit inventory type to add this lot to, if not provided this will be
319+
/// implicitly retrieved from the item lot, generally used for vendor buy back</param>
320+
/// <param name="rootItem">An optional parent item</param>
321+
/// <returns>The list of items that were created while adding the lot</returns>
322+
public async Task AddLotAsync(Lot lot, uint count, LegoDataDictionary settings = default,
323+
InventoryType inventoryType = default, Item rootItem = default)
312324
{
325+
var createdItems = new List<Item>();
326+
313327
// For players, the faction token proxy needs to be replaced with an actual faction token
314328
// If this wasn't possible, exit
315329
if (!HandleFactionToken(ref lot))
@@ -363,14 +377,15 @@ public async Task AddLotAsync(Lot lot, uint count, LegoDataDictionary settings =
363377
while (totalToAdd > 0)
364378
{
365379
var toAdd = (uint) Min(stackSize, (int) totalToAdd);
366-
var item = await Item.Instantiate(GameObject, lot, inventory, toAdd, extraInfo: settings);
380+
var item = await Item.Instantiate(GameObject, lot, inventory, toAdd, extraInfo: settings, rootItem: rootItem);
367381

368382
// Might occur if the inventory is full or an error occured during slot claiming
369383
if (item == null)
370384
return; // TODO: Message item to player with mail
371385

372386
Start(item);
373387
item.MessageCreation();
388+
createdItems.Add(item);
374389

375390
totalToAdd -= toAdd;
376391
totalAdded += toAdd;
@@ -394,6 +409,12 @@ public async Task AddLotAsync(Lot lot, uint count, LegoDataDictionary settings =
394409
await OnLotAdded.InvokeAsync(lot, (uint)totalAdded);
395410
});
396411
}
412+
413+
// Create sub items if this was a root item
414+
if (rootItem == null)
415+
foreach (var createdItem in createdItems)
416+
foreach (var subItemLot in createdItem.SubItemLots)
417+
await AddLotAsync(subItemLot, 1, default, InventoryType.Hidden, createdItem);
397418
}
398419

399420
/// <summary>
@@ -463,7 +484,7 @@ public async Task RemoveLotAsync(Lot lot, uint count, InventoryType inventoryTyp
463484
{
464485
var amountToRemove = (uint) Min((int) count, (int) itemToRemove.Count);
465486
await itemToRemove.DecrementCountAsync(amountToRemove, silent);
466-
487+
467488
count -= amountToRemove;
468489
if (count == 0)
469490
return;

Uchu.World/Objects/Components/Player/MissionInventoryComponent.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.EntityFrameworkCore;
77
using Uchu.Core;
88
using Uchu.Core.Client;
9+
using Uchu.Core.Resources;
910
using Uchu.World.Client;
1011
using Uchu.World.Objects.Components;
1112
using Uchu.World.Systems.Missions;
@@ -267,6 +268,17 @@ public bool HasMission(int id)
267268
}
268269
}
269270

271+
272+
/// <summary>
273+
/// Returns the mission with a given id from the mission inventory.
274+
/// </summary>
275+
/// <param name="missionId">The id of the mission to get from the inventory</param>
276+
/// <returns>A mission instance if the player has this mission, <c>default</c> otherwise.</returns>
277+
public MissionInstance GetMission(MissionId missionId)
278+
{
279+
return GetMission((int) missionId);
280+
}
281+
270282
/// <summary>
271283
/// Returns the mission with a given id from the mission inventory.
272284
/// </summary>
@@ -630,7 +642,8 @@ await StartUnlockableAchievementsAsync<PetTameTask>(MissionTaskType.TamePet, Pet
630642
/// <returns>A list of all the achievements a player can unlock, given the task type and the lot</returns>
631643
private MissionInstance[] UnlockableAchievements<T>(MissionTaskType type, Lot lot)
632644
where T : MissionTaskInstance => ClientCache.Achievements.Where(m =>
633-
m.Tasks.OfType<T>().Any(t => t.Type == type && t.Targets.Contains((int) lot))
645+
m.Tasks.OfType<T>().Any(t => t.Type == type
646+
&& (t.Targets.Contains((int) lot) || t.Parameters.Contains((int) lot)))
634647
&& CanAccept(m)).ToArray();
635648

636649
/// <summary>
@@ -643,6 +656,7 @@ private MissionInstance[] UnlockableAchievements<T>(MissionTaskType type, Lot lo
643656
private async Task StartUnlockableAchievementsAsync<T>(MissionTaskType type, Lot lot, Func<T, Task> progress = null)
644657
where T : MissionTaskInstance
645658
{
659+
var testMission = ClientCache.Achievements.Where(m => m.MissionId == 568);
646660
foreach (var achievement in UnlockableAchievements<T>(type, lot))
647661
{
648662
// Loading these here instead of out of the loop might seem odd but heuristically the chances of starting a

0 commit comments

Comments
 (0)