Skip to content

Starbase 3001 launchpad & teleporter #301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions Uchu.StandardScripts/Base/BaseWorldTeleporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ public class BaseWorldTeleporter : ObjectScript
protected virtual string Animation { get; }
protected virtual string AcceptIdentifier { get; } = "TransferBox";
protected virtual string CancelIdentifier { get; } = "TransferBox";
protected virtual bool CheckUserData { get; } = true;
protected virtual bool UseUserData { get; } = true;

protected virtual void ShowTransferPopup(Player player)
{
this.ShowTransferPopup(player, this.TargetZone, this.MessageBoxText);
}

protected virtual void ShowTransferPopup(Player player, int zone, string text)
{
player.Message(new DisplayMessageBoxMessage
{
Associate = player,
Identifier = this.AcceptIdentifier,
CallbackClient = GameObject,
Show = true,
UserData = this.TargetZone.ToString(),
Text = this.MessageBoxText,
UserData = zone.ToString(),
Text = text,
});
}

Expand All @@ -35,8 +40,7 @@ protected BaseWorldTeleporter(GameObject gameObject) : base(gameObject)
{
// Ensure player is answering the right message box
// Identifier differs for accept/cancel for LEGO® Club world teleporter interaction
if ((message.Identifier != this.AcceptIdentifier && message.Identifier != this.CancelIdentifier)
|| (this.CheckUserData && message.UserData != this.TargetZone.ToString()))
if ((message.Identifier != this.AcceptIdentifier && message.Identifier != this.CancelIdentifier))
return;

// If user clicked no, terminate interaction
Expand All @@ -63,6 +67,8 @@ protected BaseWorldTeleporter(GameObject gameObject) : base(gameObject)
});
player.Animate(this.Animation);

var targetZone = this.UseUserData ? int.Parse(message.UserData) : this.TargetZone;

if (this.TargetSpawnLocation != null)
player.GetComponent<CharacterComponent>().SpawnLocationName = this.TargetSpawnLocation;

Expand All @@ -74,7 +80,7 @@ protected BaseWorldTeleporter(GameObject gameObject) : base(gameObject)
this.Listen(player.OnFireServerEvent, (arguments, _) =>
{
if (arguments == "summaryComplete")
player.SendToWorldAsync((ZoneId) this.TargetZone);
player.SendToWorldAsync((ZoneId) targetZone);
});
player.Message(new DisplayZoneSummaryMessage
{
Expand Down
7 changes: 4 additions & 3 deletions Uchu.StandardScripts/General/LaunchpadEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ public override Task LoadAsync()
var id = launchpad.GameObject.Lot.GetComponentId(ComponentId.RocketLaunchComponent);
var launchpadComponent = await ClientCache.FindAsync<RocketLaunchpadControlComponent>(id);

if (launchpadComponent.TargetZone != null)
// TargetZone is 0 for the LUP launchpad, ignore it
if (launchpadComponent.TargetZone != null && launchpadComponent.TargetZone != 0)
{
var target = (ZoneId)launchpadComponent.TargetZone;

// We don't want to lock up the server on a world server request, as it may take time.
var _ = Task.Run(async () =>
{
Expand All @@ -48,4 +49,4 @@ public override Task LoadAsync()
return Task.CompletedTask;
}
}
}
}
64 changes: 64 additions & 0 deletions Uchu.StandardScripts/WorldTeleporters/FromStarbase3001.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Collections.Generic;
using Uchu.StandardScripts.Base;
using Uchu.World;
using Uchu.World.Scripting.Native;
using Uchu.World.Social;

namespace Uchu.StandardScripts.General
{
[ScriptName("L_NS_LUP_TELEPORT.lua")]
public class StarbaseTeleporter : BaseWorldTeleporter
{
protected override string TargetSpawnLocation => "NS_LW";
protected override string Animation => "lup-teleport";

public StarbaseTeleporter(GameObject gameObject) : base(gameObject)
{
var confirmationText = new Dictionary<int, string>
{
{ 1200, "%[UI_TRAVEL_TO_NS]" },
{ 1900, "%[UI_TRAVEL_TO_NEXUS_TOWER]" },
};

Listen(gameObject.OnChoiceBoxRespond, (player, message) =>
{
var targetZone = int.Parse(message.ButtonIdentifier.Split("_")[1]);
if (!confirmationText.TryGetValue(targetZone, out var text))
text = $"Do you want travel to zone {targetZone}?";

// Confirmation popup to check if the player really wants to travel to [zone]
this.ShowTransferPopup(player, targetZone, text);
});
}

// Initial handler that shows the choice box for NS/NT
protected override void ShowTransferPopup(Player player)
{
player.MessageGuiAsync("QueueChoiceBox", new Dictionary<string, object>
{
{ "callbackClient", GameObject.Id.ToString() },
{
"options", new object[]
{
new Dictionary<string, object>
{
{ "caption", "%[UI_CHOICE_NS]" },
{ "identifier", "zoneID_1200" },
{ "image", "textures/ui/zone_thumnails/Nimbus_Station.dds" },
{ "tooltipText", "%[UI_CHOICE_NS_HOVER]" },
},
new Dictionary<string, object>
{
{ "caption", "%[UI_CHOICE_NT]" },
{ "identifier", "zoneID_1900" },
{ "image", "textures/ui/zone_thumnails/Nexus_Tower.dds" },
{ "tooltipText", "%[UI_CHOICE_NT_HOVER]" },
},
}
},
{ "strIdentifier", "choiceDoor" },
{ "title", "%[UI_CHOICE_DESTINATION]" },
});
}
}
}
9 changes: 2 additions & 7 deletions Uchu.StandardScripts/WorldTeleporters/LegoClubPortal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ public class LegoClubPortal : BaseWorldTeleporter
protected override string Animation => "lup-teleport";
protected override string AcceptIdentifier => "PlayButton";
protected override string CancelIdentifier => "CloseButton";
protected override string TargetSpawnLocation => this.TargetZone switch
{
1200 => "NS_LEGO_Club",
1900 => "NS_LEGO_Club",
_ => null,
};
protected override bool CheckUserData => false;
protected override string TargetSpawnLocation => "NS_LEGO_Club";
protected override bool UseUserData => false;

protected override void ShowTransferPopup(Player player)
{
Expand Down
6 changes: 6 additions & 0 deletions Uchu.World/Handlers/GameMessages/GeneralHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,11 @@ public void MessageBoxRespondMessageHandler(MessageBoxRespondMessage message, Pl
{
message.Associate?.OnMessageBoxRespond.Invoke(player, message);
}

[PacketHandler]
public void ChoiceBoxRespondHandler(ChoiceBoxRespondMessage message, Player player)
{
message.Associate?.OnChoiceBoxRespond.Invoke(player, message);
}
}
}
14 changes: 14 additions & 0 deletions Uchu.World/Handlers/GameMessages/LUPLaunchpadHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Uchu.Core;

namespace Uchu.World.Handlers.GameMessages
{
public class LUPLaunchpadHandler : HandlerGroup
{
[PacketHandler]
public async void EnterProperty1Handler(EnterProperty1Message message, Player player)
{
if (message.Associate.TryGetComponent<LUPLaunchpadComponent>(out var lupLaunchpadComponent))
lupLaunchpadComponent.ChoiceBoxResponse(player, message.Index);
}
}
}
106 changes: 106 additions & 0 deletions Uchu.World/Objects/Components/Server/LUPLaunchpadComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Uchu.Core;
using Uchu.Core.Client;
using Uchu.World.Client;
using Uchu.World.Services;

namespace Uchu.World
{
[ServerComponent(Id = ComponentId.LUPLaunchpadComponent)]
public class LUPLaunchpadComponent : Component
{
private int[] _zones;

/// <summary>
/// Creates the component.
/// </summary>
protected LUPLaunchpadComponent()
{
Listen(OnStart, () =>
{
if (!this.GameObject.Settings.TryGetValue("MultiZoneIDs", out var multiZoneIds))
{
Logger.Error("No zone IDs defined on LUP launchpad");
return;
}

this._zones = ((string) multiZoneIds).Split(";").Select(int.Parse).ToArray();

// Listen for the player requesting to open the worlds menu.
Listen(GameObject.OnInteract, OnInteract);
});
}

private Item FindRocket(Player player)
{
// Get the player rocket.
var inventory = player.GetComponent<InventoryManagerComponent>();
var rocket = inventory[InventoryType.Models].Items.FirstOrDefault(
item => item.Lot == Lot.ModularRocket
);
if (rocket == default)
{
Logger.Error($"Could not find a valid rocket for {player}");
return null;
}

return rocket;
}

private async void OnInteract(Player player)
{
var rocket = FindRocket(player);

// Equip the rocket.
rocket.WorldState = ObjectWorldState.Attached;

await rocket.EquipAsync(true);

// Show the UI with the worlds the player can go to
player.Message(new PropertyEntranceBeginMessage
{
Associate = GameObject,
});
}

public void ChoiceBoxResponse(Player player, int index)
{
var rocket = FindRocket(player);

player.Message(new FireEventClientSideMessage
{
Associate = GameObject,
Arguments = "RocketEquipped",
Target = rocket,
Sender = player,
});

// Set the player as landing by rocket for the next zone.
if (!player.TryGetComponent<CharacterComponent>(out var characterComponent))
return;
characterComponent.LandingByRocket = true;

// Listen for ZonePlayer event
Delegate listener = null;
listener = Listen(player.OnFireServerEvent, (name, message) =>
{
if (name != "ZonePlayer")
return;

// Player is leaving zone, so we can stop listening now
ReleaseListener(listener);

var _ = Task.Run(async () =>
{
player.GetComponent<CharacterComponent>().LaunchedRocketFrom = Zone.ZoneId;
var success = await player.SendToWorldAsync((ZoneId) this._zones[index]);

if (!success)
player.SendChatMessage($"Failed to transfer to {this._zones[index]}, please try later.");
});
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ protected RocketLaunchpadComponent()
/// <param name="player">Player who requested launching.</param>
public async void OnInteract(Player player)
{
// LUP launchpad is handled in its own component
if (GameObject.TryGetComponent<LUPLaunchpadComponent>(out _))
return;

// Get the player rocket.
var rocket = player.GetComponent<InventoryManagerComponent>()[InventoryType.Models].Items.FirstOrDefault(
item => item.Lot == Lot.ModularRocket
Expand Down
4 changes: 4 additions & 0 deletions Uchu.World/Objects/GameObjects/GameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ public int GameMasterLevel

public Event<Player, MessageBoxRespondMessage> OnMessageBoxRespond { get; }

public Event<Player, ChoiceBoxRespondMessage> OnChoiceBoxRespond { get; }

#endregion

#region Macro
Expand Down Expand Up @@ -142,6 +144,8 @@ protected GameObject()

OnMessageBoxRespond = new Event<Player, MessageBoxRespondMessage>();

OnChoiceBoxRespond = new Event<Player, ChoiceBoxRespondMessage>();

Listen(OnStart, () =>
{
foreach (var component in Components.ToArray()) Start(component);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Uchu.World
{
[ServerGameMessagePacketStruct]
public struct PropertyEntranceBeginMessage
{
public GameObject Associate { get; set; }
public GameMessageId GameMessageId => GameMessageId.PropertyEntranceBegin;
}
}
35 changes: 25 additions & 10 deletions Uchu.World/Social/Amf3Helper.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using RakDotNet.IO;

Expand Down Expand Up @@ -56,13 +57,16 @@ public static void Write(BitWriter writer, object value)
break;
case IDictionary<string, object> dict:
writer.Write((byte) Amf3Type.Array);
WriteArray(writer, dict);
WriteDict(writer, dict);
break;
case Array array:
writer.Write((byte) Amf3Type.Array);
WriteArray(writer, array);
break;
case null:
writer.Write((byte) Amf3Type.Undefined);
break;
}

}

public static void WriteText(BitWriter writer, string value)
Expand All @@ -77,15 +81,26 @@ public static void WriteText(BitWriter writer, string value)
}
}

public static void WriteArray(BitWriter writer, IDictionary<string, object> dict)
public static void WriteDict(BitWriter writer, IDictionary<string, object> dict) => WriteArrayAndDict(writer, dict: dict);

public static void WriteArray(BitWriter writer, Array array) => WriteArrayAndDict(writer, array: array);

public static void WriteArrayAndDict(BitWriter writer, Array array = null, IDictionary<string, object> dict = null)
{
WriteNumber(writer, 0x01);
foreach (var (key, value) in dict)
{
WriteText(writer, key);
Write(writer, value);
}
writer.Write((byte) Amf3Type.Null);
var arrayLength = (uint) (array?.Length ?? 0);
WriteNumber(writer, (arrayLength << 1) | 0x01);
if (dict != null)
foreach (var (key, value) in dict)
{
WriteText(writer, key);
Write(writer, value);
}
WriteText(writer, "");
if (array != null)
foreach (var value in array)
{
Write(writer, value);
}
}
}
}