diff --git a/TrekSharp.AdventureTools/Shared/CharacterEditorPopoutTab.razor b/TrekSharp.AdventureTools/Shared/CharacterEditorPopoutTab.razor index 544f9ae..a692486 100644 --- a/TrekSharp.AdventureTools/Shared/CharacterEditorPopoutTab.razor +++ b/TrekSharp.AdventureTools/Shared/CharacterEditorPopoutTab.razor @@ -8,17 +8,16 @@
+ @if (Character is SupportCharacter sc) { + + @if (sc.IsPlayerEquivalent) { + + } else { + + } + }
- @if (Character is SupportCharacter sc) { - if (!sc.HasBeenIntroduced) { -
- Player Options -
-
- -
- } - } +
Other
@@ -75,6 +74,13 @@ } } + private void upgradeToPlayer() { + if (HasCharacter && Character is SupportCharacter sc) { + this.Data.Supports.Remove(sc); + this.Data.Party.Add(sc.UpgradeToPlayer()); + } + } + private ConfirmationDialog confirm; private void confirmDelete() { confirm.Open($"Are you sure you want to delete the character '{this.Character.Name}'?", () => Delete()); diff --git a/TrekSharp.AdventureTools/Shared/FilePopup.razor b/TrekSharp.AdventureTools/Shared/FilePopup.razor index 656ff6f..1557f06 100644 --- a/TrekSharp.AdventureTools/Shared/FilePopup.razor +++ b/TrekSharp.AdventureTools/Shared/FilePopup.razor @@ -37,6 +37,8 @@ private Popup popup; private AssetImporter importer; + [Parameter] public Action OnFileLoaded {get; set;} + public void Open() { popup.Open(); } @@ -57,7 +59,7 @@ } private void onAppDataLoaded(AppData data) { this.Data.Overwrite(data); - this.StateHasChanged(); + OnFileLoaded?.Invoke(); this.NavigateHome(); } diff --git a/TrekSharp.AdventureTools/Shared/MilestoneEditor.razor b/TrekSharp.AdventureTools/Shared/MilestoneEditor.razor index 4c3c092..15db8bf 100644 --- a/TrekSharp.AdventureTools/Shared/MilestoneEditor.razor +++ b/TrekSharp.AdventureTools/Shared/MilestoneEditor.razor @@ -65,7 +65,7 @@ @if (Character is PlayableCharacter pc) { - pc)> + } @@ -89,7 +89,7 @@ @if (Character is PlayableCharacter pc) { - pc)> + } @@ -129,8 +129,7 @@ spotlightAttributeDelta = new Attributes(0); if (spotlightTalentSwap != null) { - spotlightTalentSwap.DeletedTalent = null; - spotlightTalentSwap.SelectedTalent = null; + spotlightTalentSwap.Deselect(); } arcDisciplineDelta = new Disciplines(0); @@ -138,7 +137,7 @@ arcNewFocus = null; arcNewValue = null; if (arcNewTalent != null) - arcNewTalent.SelectedTalent = null; + arcNewTalent.Deselect(); StateHasChanged(); } @@ -153,9 +152,11 @@ Character.Attributes.Add(spotlightAttributeDelta); if (Character is PlayableCharacter pc) { - if (spotlightTalentSwap != null && spotlightTalentSwap.DeletedTalent != null && spotlightTalentSwap.SelectedTalent != null) { - pc.Talents.Remove(spotlightTalentSwap.DeletedTalent); - pc.Talents.Add(spotlightTalentSwap.SelectedTalent); + if (pc.Talents == null) { + pc.Talents = new List(); + } + if (spotlightTalentSwap != null) { + spotlightTalentSwap.Swap(); } } @@ -169,8 +170,14 @@ Character.Values.Add(arcNewValue); } if (Character is PlayableCharacter ppc) { - if (arcNewTalent != null && arcNewTalent.SelectedTalent != null) { - ppc.Talents.Add(arcNewTalent.SelectedTalent); + if (arcNewTalent != null ) { + var t = arcNewTalent.Talent; + if (t != null) { + if (ppc.Talents == null) { + ppc.Talents = new List(); + } + ppc.Talents.Add(t); + } } } OnSave?.Invoke(); @@ -190,13 +197,13 @@ private Disciplines normalDisciplineDelta = new Disciplines(0); private Attributes spotlightAttributeDelta = new Attributes(0); - private TalentPicker spotlightTalentSwap; + private TalentSwap spotlightTalentSwap; private Disciplines arcDisciplineDelta = new Disciplines(0); private Attributes arcAttributeDelta = new Attributes(0); private string arcNewFocus = null; private string arcNewValue = null; - private TalentPicker arcNewTalent; + private TalentSelect arcNewTalent; } \ No newline at end of file diff --git a/TrekSharp.AdventureTools/Shared/NavMenu.razor b/TrekSharp.AdventureTools/Shared/NavMenu.razor index 51e3b23..cc28d1f 100644 --- a/TrekSharp.AdventureTools/Shared/NavMenu.razor +++ b/TrekSharp.AdventureTools/Shared/NavMenu.razor @@ -140,7 +140,7 @@ - + @code { diff --git a/TrekSharp.AdventureTools/Shared/Select.razor b/TrekSharp.AdventureTools/Shared/Select.razor new file mode 100644 index 0000000..4bb4e77 --- /dev/null +++ b/TrekSharp.AdventureTools/Shared/Select.razor @@ -0,0 +1,35 @@ +@typeparam T + + + + @if(Items != null) { + foreach (var item in Items) { + + +@code { + [Parameter] public IEnumerable Items {get; set;} + [Parameter] public string Placeholder {get; set;} + private string selectedString; + public T Selected => Items == null ? default(T) : Items.Where(item => string.Equals(Stringify(item), selectedString, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); + + private string ComponentGuid; + + [Parameter] public Func Stringify {get; set;} = defaultStringify; + + private static string defaultStringify(T value) { + return value?.ToString(); + } + + protected override void OnInitialized() { + base.OnInitialized(); + ComponentGuid = System.Guid.NewGuid().ToString(); + } + + public void Deselect() { + selectedString = null; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/TrekSharp.AdventureTools/Shared/TalentPicker.razor b/TrekSharp.AdventureTools/Shared/TalentPicker.razor deleted file mode 100644 index 34824f5..0000000 --- a/TrekSharp.AdventureTools/Shared/TalentPicker.razor +++ /dev/null @@ -1,98 +0,0 @@ -@using System.Globalization - - -@if (RequireDelete) { -
-
- - REPLACE A TALENT - -
-
-

- Select one talent to be replaced with a new talent. -

- @if(GetPlayer() == null) { - ERROR No Character - } else { - foreach (var talent in GetPlayer().Talents) { -
-
- -
-
- @talent.Description -   -
-
- -
-
- } - } -} -@if (!RequireDelete || DeletedTalent != null) { -
-
- - ADD TALENT - -
-
-
-
- - -
- @if(GetPlayer() == null) { - ERROR No Character - } - @foreach (var talent in allTalents()) { -
-
- -
-
- @talent.Description -   -
-
- -
-
- } -
-} - -@code { - - [Parameter] public bool RequireDelete {get; set;} = false; - public CharacterTalent DeletedTalent; - [Parameter] public Func GetPlayer {get; set;} - private RulebookPicker Books; - private string talentFilter = null; - public CharacterTalent SelectedTalent; - - private IEnumerable allTalents() { - var @char = this.GetPlayer(); // Cached once across entire filter - var books = Books?.EnabledRulebooks; - if (@char == null || books == null) { - return Enumerable.Empty(); - } - return books - .SelectMany(book => book.Talents) - .Where(talent => - @char != null && talent.CanBeUsedBy(@char) // Character can use talent (species or skill rating restrictions) - //&& !characterTalents.Contains(talent) // Character does not already have this talent - && ( - string.IsNullOrEmpty(talentFilter) - || CultureInfo.InvariantCulture.CompareInfo.IndexOf(talent.Name, talentFilter, CompareOptions.IgnoreCase) >= 0 - ) - ); - } - -} \ No newline at end of file diff --git a/TrekSharp.AdventureTools/Shared/TalentSelect.razor b/TrekSharp.AdventureTools/Shared/TalentSelect.razor new file mode 100644 index 0000000..1dce75c --- /dev/null +++ b/TrekSharp.AdventureTools/Shared/TalentSelect.razor @@ -0,0 +1,25 @@ + + +@code { + + private Select select; + + public CharacterTalent Talent => select?.Selected; + + private List talents; + + [Parameter] public Character Character {get; set;} + + protected override void OnInitialized() { + talents = new Data.RulebookContainer() + .AllRulebooks + .SelectMany(book => book.Value.Talents) + .Where(talent => Character == null || talent.CanBeUsedBy(Character)) + .ToList(); + } + + public void Deselect() { + select?.Deselect(); + } + +} \ No newline at end of file diff --git a/TrekSharp.AdventureTools/Shared/TalentSwap.razor b/TrekSharp.AdventureTools/Shared/TalentSwap.razor new file mode 100644 index 0000000..9ca3cf3 --- /dev/null +++ b/TrekSharp.AdventureTools/Shared/TalentSwap.razor @@ -0,0 +1,42 @@ +
+
+ + DELETE + +
+
+
+ +
+ +
+
+ + ADD + +
+
+
+ +
+ +@code { + private Select toDelete; + private TalentSelect toAdd; + + [Parameter] public PlayableCharacter Character {get; set;} + + public void Swap() { + var delete = toDelete.Selected; + var add = toAdd.Talent; + if (delete != null && add != null) { + Character.Talents.Remove(delete); + Character.Talents.Add(add); + } + } + + public void Deselect() { + toDelete.Deselect(); + toAdd.Deselect(); + } +} \ No newline at end of file diff --git a/TrekSharp/src/Attributes.cs b/TrekSharp/src/Attributes.cs index 500ed4d..5f48593 100644 --- a/TrekSharp/src/Attributes.cs +++ b/TrekSharp/src/Attributes.cs @@ -136,6 +136,15 @@ public Attributes () : this(0) { } + public Attributes(Attributes other) { + this.Control = other.Control; + this.Daring = other.Daring; + this.Fitness = other.Daring; + this.Insight = other.Insight; + this.Presence = other.Presence; + this.Reason = other.Reason; + } + public Attributes (int values) { this[0] = values; this[1] = values; diff --git a/TrekSharp/src/Character.cs b/TrekSharp/src/Character.cs index 3755302..648491f 100644 --- a/TrekSharp/src/Character.cs +++ b/TrekSharp/src/Character.cs @@ -70,10 +70,33 @@ public override string ToString() { public class PlayableCharacter : Character { public List Talents {get; set;} + public bool HasTalents => Talents != null && Talents.Count > 0; } public class SupportCharacter : PlayableCharacter { - public bool HasBeenIntroduced => Talents != null && Values != null; + public bool IsPlayerEquivalent => HasTalents && Focuses.Count >= 6 && Values.Count >= 4; + + public PlayerCharacter UpgradeToPlayer(string environment = null, string upbringing = null) { + return new PlayerCharacter { + Name = this.Name, + Rank = this.Rank, + Assignment = this.Assignment, + Species = this.Species, + Attributes = new Attributes(this.Attributes), + Disciplines = new Disciplines(this.Disciplines), + Focuses = new List(this.Focuses), + Values = new List(this.Values), + Avatar = this.Avatar, + Bio = null, + UsedStress = this.UsedStress, + Resistance = this.Resistance, + Equipment = new List(this.Equipment), + Condition = this.Condition, + Environment = environment, + Upbringing = upbringing, + Determination = 1, + }; + } } public class PlayerCharacter : PlayableCharacter { diff --git a/TrekSharp/src/Disciplines.cs b/TrekSharp/src/Disciplines.cs index 7897d9e..c891f1f 100644 --- a/TrekSharp/src/Disciplines.cs +++ b/TrekSharp/src/Disciplines.cs @@ -135,6 +135,15 @@ public DisciplineEnumerator Enumerate() { public Disciplines() : this(0) {} + public Disciplines(Disciplines other) { + this.Command = other.Command; + this.Conn = other.Conn; + this.Engineering = other.Engineering; + this.Medicine = other.Medicine; + this.Science = other.Science; + this.Security = other.Security; + } + public Disciplines (int values) { this[0] = values; this[1] = values; diff --git a/TrekSharp/src/Rulebooks/Core.cs b/TrekSharp/src/Rulebooks/Core.cs index a4e8c12..d1b3ecf 100644 --- a/TrekSharp/src/Rulebooks/Core.cs +++ b/TrekSharp/src/Rulebooks/Core.cs @@ -105,7 +105,7 @@ List items new SpeciesRestrictedTalent("Human", "Resolute", "You are indomitable, and unwilling to succumb to adversity. You increase your maximum Stress by 3."){ StressModifier = 3 }, new SpeciesRestrictedTalent("Human", "Spirit of Discovery", "You have the drive, spirit, and courage to voyage into the unknown. You may spend one Determination to add three points of Momentum to the group pool."), new SpeciesRestrictedTalent("Tellarite", "Incisive Scrutiny", "You have a knack for finding weak spots in arguments, theories, and machines alike to glean information from them, learning about things and how they respond to pressure against vulnerable points. When you succeed at a Task using Control or Insight, you gain one bonus Momentum which may be used for an Obtain Information Spend."), - new SpeciesRestrictedTalent("Tellarite", "Sturdy", "YOu have a blend of physical resilience and mental fortitude such that you're difficult to subdue. You reduce the cost to resist being knocked prone by the Knockdown damage effect bty 1, to a minimum of 0, and gain +1 Resistance against all non-lethal attacks."), + new SpeciesRestrictedTalent("Tellarite", "Sturdy", "You have a blend of physical resilience and mental fortitude such that you're difficult to subdue. You reduce the cost to resist being knocked prone by the Knockdown damage effect bty 1, to a minimum of 0, and gain +1 Resistance against all non-lethal attacks."), new SpeciesRestrictedTalent("Trill", "Former Initiate", "You joined the Initiate program, hoping to be chosen by the Symbiosis Commission to become joined. As there are far more initiates than there are Symbionts, you were one of the many who failed. When you attempt a task using Control or Reason, and spend Determination to buy a bonus d20 for that Task, you may re-roll your dice pool."), new SpeciesRestrictedTalent("Trill", "Joined", "You have a symbiont, with lifetimes of memories to draw upon, Once per mission, you may declare that a former host had expertise in a relevant skill or field of study; you gain a single Focus for the remainder of the scene as you draw upon those memories."), new SpeciesRestrictedTalent("Vulkan", "Mind-Meld", "You have undergone training in telepathic techniques that allow the melding of minds through physical contact. This will always require a Task with Difficulty of at least 1, which can be opposed by an unwilling participant. If successful, you link minds sharing thoughts and memories; Momentum may be spent to gain more information, or perform deeper telepathic exchanges."),