Skip to content

Commit

Permalink
Added shops
Browse files Browse the repository at this point in the history
  • Loading branch information
Redcrafter committed May 13, 2022
1 parent c62d22a commit 07e098c
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 21 deletions.
17 changes: 14 additions & 3 deletions Server/MapData.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
using System.Text.Json;
using Extractor;
using Resource = Extractor.Resource;

namespace Server {
class NpcData : NPCName {
public int Action1 { get; set; }
public int Action2 { get; set; }
public int Action3 { get; set; }
public int Action4 { get; set; }

public static NpcData[] Load(string path) {
return JsonSerializer.Deserialize<NpcData[]>(System.IO.File.ReadAllText(path));
}
}

class MapData {
public Teleport[] Teleporters { get; set; }
public NPCName[] Npcs { get; set; }
public Resource[] Resources { get; set; }
public NpcData[] Npcs { get; set; }
public Extractor.Resource[] Resources { get; set; }
}
}
15 changes: 12 additions & 3 deletions Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Program {
internal static Quest[] quests;
internal static SkillInfo[] skills;
internal static ProdRule[] prodRules;
internal static Dictionary<int, Shop> Shops;

internal static List<Client> clients = new List<Client>();

Expand Down Expand Up @@ -289,7 +290,6 @@ static void Main(string[] args) {
var archive = SeanArchive.Extract("./client_table_eng.sdb");

teleporters = Teleport .Load(archive.First(x => x.Name == "teleport_list.txt"));
var npcs = NPCName .Load(archive.First(x => x.Name == "npc_list.txt"));
resources = Extractor.Resource.Load(archive.First(x => x.Name == "res_list.txt"));
lootTables = ResCounter.Load(archive.First(x => x.Name == "res_counter.txt"));
items = ItemAtt .Load(archive.First(x => x.Name == "item_att.txt"));
Expand All @@ -300,6 +300,15 @@ static void Main(string[] args) {
var mapList = MapList.Load(archive.First(x => x.Name == "map_list.txt"));

var dialogs = JsonSerializer.Deserialize<JsonElement[]>(File.ReadAllText("./dialog_data.json"));
var npcs = NpcData.Load("./npc_data.json");
var shops = Shop.Load("./shop_data.json");

Shops = new Dictionary<int, Shop>();
foreach(var shop in shops) {
foreach(var npc in shop?.Npcs) {
Shops[npc] = shop;
}
}

dialogData = new Dictionary<int, DialogData[]>();
foreach(var npc in npcs) {
Expand Down Expand Up @@ -353,8 +362,8 @@ static void Main(string[] args) {
}

Debug.Assert(teleporters.All(x => x.FromMap == 0 || maps[x.FromMap] != null)); // all teleporters registered
Debug.Assert(npcs.All(x => x.MapId == 0 || maps[x.MapId] != null)); // all teleporters registered
Debug.Assert(resources.All(x => x.MapId == 0 || maps[x.MapId] != null)); // all teleporters registered
Debug.Assert(npcs.All(x => x.MapId == 0 || maps[x.MapId] != null)); // all npcs registered
Debug.Assert(resources.All(x => x.MapId == 0 || maps[x.MapId] != null)); // all resources registered

var sb = new MySqlConnectionStringBuilder {
Server = "127.0.0.1",
Expand Down
22 changes: 11 additions & 11 deletions Server/Protocols/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ static void SendAddPlayers(Client client, Client[] clients) {
}

// 02_03
static PacketBuilder BuildDeletePlayer(Client client) {
public static PacketBuilder BuildDeletePlayer(Client client) {
var b = new PacketBuilder();

b.WriteByte(0x2); // first switch
Expand Down Expand Up @@ -837,21 +837,21 @@ static void SendTeleporters(Client client, Teleport[] teleporters) {
b.Send(client);
}

static void writeNpcData(PacketBuilder w, NPCName npc) {
w.WriteInt(npc.Id); // entity/npc id
w.WriteInt(npc.X); // x
w.WriteInt(npc.Y); // y
static void writeNpcData(PacketBuilder w, NpcData npc) {
w.WriteInt(npc.Id);
w.WriteInt(npc.X);
w.WriteInt(npc.Y);

w.WriteByte((byte)npc.Rotation); // rotation
w.WriteByte((byte)npc.Rotation);
w.Write0(3); // unused

w.WriteInt(0);
w.WriteInt(0);
w.WriteInt(0);
w.WriteInt(0);
w.WriteInt(npc.Action1);
w.WriteInt(npc.Action2);
w.WriteInt(npc.Action3);
w.WriteInt(npc.Action4);
}
// 02_16
static void SendNpcs(Client client, NPCName[] npcs) {
static void SendNpcs(Client client, NpcData[] npcs) {
// create npcs
var b = new PacketBuilder();

Expand Down
141 changes: 137 additions & 4 deletions Server/Protocols/Store.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,150 @@
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Text.Json;
using Microsoft.Extensions.Logging;

namespace Server.Protocols {
enum ShopType : byte {
Money = 0,
DreamFragments = 1,
TokenNormal = 2,
TokenSpecial = 3,
Ticket = 4,
}

class ShopItem {
public int Id { get; set; }
public int Price { get; set; }
public int Count { get; set; }
public int Friendship { get; set; }
}

class Shop {
public int[] Npcs { get; set; }
public int Village { get; set; }
public ShopType Type { get; set; }
public ShopItem[] Items { get; set; }

public static Shop[] Load(string path) {
return JsonSerializer.Deserialize<Shop[]>(File.ReadAllText(path));
}
}

static class Store {
public static void Handle(Client client) {
var id = client.ReadByte();
switch(id) {
// case 0x01: // 0054d96c
// case 0x02: //
// case 0x03: //
case 0x01: // 0054d96c
OpenStore(client);
break;
case 0x02: // 0054d9a4
BuyItem(client);
break;
case 0x03: // 0054da30
SellItem(client);
break;
default:
client.Logger.LogWarning($"Unknown Packet 0B_{id:X2}");
break;
}
}

#region Request
// 0B_01
static void OpenStore(Client client) {
var npcId = client.ReadInt32();

if (!Program.Shops.TryGetValue(npcId, out var store)) {
return;
}

if(store != null) {
SendStoreInfo(client, npcId, store);
}
}

// 0B_02
static void BuyItem(Client client) {
var npcId = client.ReadInt32();
var itemNum = client.ReadByte();

if(!Program.Shops.TryGetValue(npcId, out var store)) {
return;
}

if(itemNum >= store.Items.Length) {
throw new ArgumentOutOfRangeException(nameof(itemNum));
}

var item = store.Items[itemNum];

var canAfford = item.Price <= store.Type switch {
ShopType.Money => client.Player.Money,
ShopType.TokenNormal => client.Player.NormalTokens,
ShopType.TokenSpecial => client.Player.SpecialTokens,
ShopType.Ticket => client.Player.Tickets,
_ => throw new ArgumentOutOfRangeException(nameof(store.Type))
};

if(canAfford && client.AddItem(item.Id, item.Count)) {
client.Player.Money -= item.Price;
Inventory.SendSetMoney(client);
}
}

// 0B_03
static void SellItem(Client client) {
var npcId = client.ReadInt32();
var itemSlot = client.ReadInt32() - 1;

if(itemSlot >= client.Player.InventorySize) {
throw new ArgumentOutOfRangeException(nameof(itemSlot));
}

var item = client.Player.Inventory[itemSlot];
if(item.Id == 0) {
throw new ArgumentOutOfRangeException(nameof(itemSlot));
}

var itemData = Program.items[item.Id];

client.Player.Inventory[itemSlot] = InventoryItem.Empty;
Inventory.SendSetItem(client, InventoryItem.Empty, (byte)(itemSlot + 1));

client.Player.Money += itemData.Price * item.Count;
Inventory.SendSetMoney(client);
}
#endregion

#region Response
// 0B_01
static void SendStoreInfo(Client client, int npc, Shop store) {
var b = new PacketBuilder();

b.WriteByte(0x0B); // first switch
b.WriteByte(0x01); // second switch

b.WriteInt(npc);

b.WriteInt(store.Village);
b.WriteByte((byte)store.Type);

foreach (var item in store.Items) {
b.WriteInt(item.Id);
b.WriteInt(item.Count);
b.WriteInt(item.Price);
b.WriteInt(item.Friendship);
}

// pad to multiple of 50 because the game has bad code
int left = 50 - store.Items.Length % 50;
for(int i = 0; i < left; i++) {
b.WriteInt(0);
}
b.WriteInt(-1); // end

b.Send(client);
}
#endregion
}
}

0 comments on commit 07e098c

Please sign in to comment.