diff --git a/Assets/Scripts/CGS/CardModel.cs b/Assets/Scripts/CGS/CardModel.cs index d0c12b61f..fca17fb47 100644 --- a/Assets/Scripts/CGS/CardModel.cs +++ b/Assets/Scripts/CGS/CardModel.cs @@ -407,12 +407,12 @@ public void OnChangeRotation(Quaternion rotation) transform.rotation = rotation; } - public static void ResetRotation(CardStack cardStack, CardModel cardModel) + public static void Rotate90(CardModel cardModel) { if (cardModel == null || (cardModel.IsOnline && !cardModel.hasAuthority)) return; - cardModel.transform.rotation = Quaternion.identity; + cardModel.transform.rotation *= Quaternion.Euler(0, 0, -90); if (cardModel.IsOnline) cardModel.CmdUpdateRotation(cardModel.transform.rotation); } @@ -429,6 +429,16 @@ public static void ToggleRotation90(CardModel cardModel) cardModel.CmdUpdateRotation(cardModel.transform.rotation); } + public static void ResetRotation(CardStack cardStack, CardModel cardModel) + { + if (cardModel == null || (cardModel.IsOnline && !cardModel.hasAuthority)) + return; + + cardModel.transform.rotation = Quaternion.identity; + if (cardModel.IsOnline) + cardModel.CmdUpdateRotation(cardModel.transform.rotation); + } + public static void ShowCard(CardStack cardStack, CardModel cardModel) { if (cardModel == null || (cardModel.IsOnline && !cardModel.hasAuthority)) diff --git a/Assets/Scripts/CGS/Inputs.cs b/Assets/Scripts/CGS/Inputs.cs index 6569bb875..eae34fb70 100644 --- a/Assets/Scripts/CGS/Inputs.cs +++ b/Assets/Scripts/CGS/Inputs.cs @@ -7,7 +7,6 @@ public static class Inputs public const string CardViewer = "CardViewer"; public const string Column = "Column"; public const string Delete = "Delete"; - public const string Draw = "Draw"; public const string Filter = "Filter"; public const string FocusName = "FocusName"; public const string FocusText = "FocusText"; diff --git a/Assets/Scripts/CGS/Menus/CardSearchMenu.cs b/Assets/Scripts/CGS/Menus/CardSearchMenu.cs index 4a138482a..fcb7362e1 100644 --- a/Assets/Scripts/CGS/Menus/CardSearchMenu.cs +++ b/Assets/Scripts/CGS/Menus/CardSearchMenu.cs @@ -390,12 +390,8 @@ public string Filters filters += "set:" + SetCodeFilter + "; "; foreach (PropertyDef property in CardGameManager.Current.CardProperties) { switch (property.Type) { - case PropertyType.Integer: - if (IntMinPropertyFilters.ContainsKey(property.Name)) - filters += property.Name + ">=" + IntMinPropertyFilters[property.Name] + "; "; - if (IntMaxPropertyFilters.ContainsKey(property.Name)) - filters += property.Name + "<=" + IntMaxPropertyFilters[property.Name] + "; "; - break; + case PropertyType.ObjectEnum: + case PropertyType.ObjectEnumList: case PropertyType.StringEnum: case PropertyType.StringEnumList: if (!EnumPropertyFilters.ContainsKey(property.Name)) @@ -404,6 +400,18 @@ public string Filters if (enumDef != null) filters += property.Name + ":=" + EnumPropertyFilters[property.Name] + "; "; break; + case PropertyType.Integer: + if (IntMinPropertyFilters.ContainsKey(property.Name)) + filters += property.Name + ">=" + IntMinPropertyFilters[property.Name] + "; "; + if (IntMaxPropertyFilters.ContainsKey(property.Name)) + filters += property.Name + "<=" + IntMaxPropertyFilters[property.Name] + "; "; + break; + case PropertyType.Object: + case PropertyType.ObjectList: + case PropertyType.Number: + case PropertyType.Boolean: + case PropertyType.StringList: + case PropertyType.EscapedString: case PropertyType.String: default: if (StringPropertyFilters.ContainsKey(property.Name)) diff --git a/Assets/Scripts/CGS/PlayMode/Multiplayer/LobbyDiscovery.cs b/Assets/Scripts/CGS/PlayMode/Multiplayer/LobbyDiscovery.cs index 8c71b46d5..80259a4cd 100644 --- a/Assets/Scripts/CGS/PlayMode/Multiplayer/LobbyDiscovery.cs +++ b/Assets/Scripts/CGS/PlayMode/Multiplayer/LobbyDiscovery.cs @@ -37,7 +37,7 @@ IEnumerator WaitToStartBroadcast() public void SearchForHost() { if (Application.internetReachability != NetworkReachability.ReachableViaLocalAreaNetwork) { - if (Application.internetReachability != NetworkReachability.ReachableViaCarrierDataNetwork) + if (Debug.isDebugBuild) //(Application.internetReachability != NetworkReachability.ReachableViaCarrierDataNetwork) CardGameManager.Instance.Messenger.Show(ListenErrorMessage); return; } diff --git a/Assets/Scripts/CGS/PlayMode/PlayMode.cs b/Assets/Scripts/CGS/PlayMode/PlayMode.cs index 9ac569171..d905778b9 100644 --- a/Assets/Scripts/CGS/PlayMode/PlayMode.cs +++ b/Assets/Scripts/CGS/PlayMode/PlayMode.cs @@ -57,14 +57,19 @@ void Update() if (CardInfoViewer.Instance.IsVisible || !Input.anyKeyDown || CardGameManager.TopMenuCanvas != null) return; - if (Input.GetButtonDown(Inputs.Draw)) - Deal(1); - else if (Input.GetButtonDown(Inputs.Load)) + if (Input.GetButtonDown(Inputs.Load)) ShowDeckMenu(); + else if (Input.GetButtonDown(Inputs.Save)) + ShowDiceMenu(); else if (Input.GetButtonDown(Inputs.Filter)) ShowCardsMenu(); - else if (Input.GetButtonDown(Inputs.Sort)) - ShowDiceMenu(); + else if (Input.GetButtonDown(Inputs.Horizontal)) + { + if (Input.GetAxis(Inputs.Horizontal) > 0) + Deal(1); + else + Burn(1); + } else if (Input.GetKeyDown(KeyCode.Escape) || Input.GetButtonDown(Inputs.Cancel)) PromptBackToMainMenu(); } @@ -171,6 +176,12 @@ public void Deal(int cardCount) AddCardsToHand(PopDeckCards(cardCount)); } + public void Burn(int cardCount) + { + foreach(Card card in PopDeckCards(cardCount)) + CatchDiscard(card); + } + public List PopDeckCards(int cardCount) { List cards = new List(cardCount); @@ -204,7 +215,7 @@ public void AddCardToPlay(CardStack cardStack, CardModel cardModel) public void SetPlayActions(CardStack cardStack, CardModel cardModel) { - cardModel.DoubleClickAction = CardModel.ToggleRotation90; + cardModel.DoubleClickAction = CardModel.Rotate90; cardModel.SecondaryDragAction = cardModel.Rotate; } diff --git a/Assets/Scripts/CardGameDef/Card.cs b/Assets/Scripts/CardGameDef/Card.cs index 8b6872909..b0b5f9e44 100644 --- a/Assets/Scripts/CardGameDef/Card.cs +++ b/Assets/Scripts/CardGameDef/Card.cs @@ -104,12 +104,20 @@ public int CompareTo(Card other) { switch (property.Def.Type) { + case PropertyType.ObjectEnum: + case PropertyType.ObjectEnumList: case PropertyType.StringEnum: case PropertyType.StringEnumList: case PropertyType.Integer: int thisValue = GetPropertyValueInt(property.Def.Name); int otherValue = other.GetPropertyValueInt(property.Def.Name); return thisValue.CompareTo(otherValue); + case PropertyType.Object: + case PropertyType.ObjectList: + case PropertyType.Number: + case PropertyType.Boolean: + case PropertyType.StringList: + case PropertyType.EscapedString: case PropertyType.String: default: return string.Compare(property.Value, other.Properties[property.Def.Name].Value, StringComparison.Ordinal); diff --git a/Assets/Scripts/CardGameDef/CardGame.cs b/Assets/Scripts/CardGameDef/CardGame.cs index 5486fa7fc..b27c17f80 100644 --- a/Assets/Scripts/CardGameDef/CardGame.cs +++ b/Assets/Scripts/CardGameDef/CardGame.cs @@ -39,6 +39,12 @@ public class CardGame [JsonProperty] public int AllCardsUrlPageCount { get; set; } = 1; + [JsonProperty] + public string AllCardsUrlPageCountIdentifier { get; set; } = ""; + + [JsonProperty] + public int AllCardsUrlPageCountDivisor { get; set; } = 1; + [JsonProperty] public string AllCardsUrlPageIdentifier { get; set; } = "?page="; @@ -153,6 +159,9 @@ public class CardGame [JsonProperty] public UnityEngine.Vector2 PlayAreaSize { get; set; } = new UnityEngine.Vector2(23.5f, 20.25f); + [JsonProperty] + public bool ReprintsInCardObjectList { get; set; } + [JsonProperty] public string RulesUrl { get; set; } = ""; @@ -212,7 +221,8 @@ public IEnumerator Download() Directory.Delete(initialDirectory, true); } - yield return UnityExtensionMethods.SaveUrlToFile(AllCardsUrl, CardsFilePath + string cardsUrl = AllCardsUrl + (AllCardsUrlPageCount > 1 ? AllCardsUrlPageIdentifier + "1" : string.Empty); + yield return UnityExtensionMethods.SaveUrlToFile(cardsUrl, CardsFilePath + (AllCardsZipped ? UnityExtensionMethods.ZipExtension : string.Empty)); if (AllCardsZipped) UnityExtensionMethods.ExtractZip(CardsFilePath + UnityExtensionMethods.ZipExtension, FilePathBase); @@ -302,6 +312,11 @@ public void LoadJsonFromFile(string file, LoadJTokenDelegate load, string dataId JToken root = JToken.Parse(File.ReadAllText(file)); foreach (JToken jToken in !string.IsNullOrEmpty(dataId) ? root[dataId] : root as JArray ?? (IJEnumerable)((JObject)root).PropertyValues()) load(jToken, Set.DefaultCode); + + if (!string.IsNullOrEmpty(AllCardsUrlPageCountIdentifier) && root[AllCardsUrlPageCountIdentifier] != null) + AllCardsUrlPageCount = root.Value(AllCardsUrlPageCountIdentifier); + if (AllCardsUrlPageCountDivisor > 0) + AllCardsUrlPageCount = UnityEngine.Mathf.CeilToInt(((float)AllCardsUrlPageCount) / AllCardsUrlPageCountDivisor); } public void LoadCardFromJToken(JToken cardJToken, string defaultSetCode) @@ -314,31 +329,68 @@ public void LoadCardFromJToken(JToken cardJToken, string defaultSetCode) return; string cardName = cardJToken.Value(CardNameIdentifier) ?? string.Empty; - string cardSet = cardJToken.Value(CardSetIdentifier) ?? defaultSetCode; Dictionary cardProperties = new Dictionary(); foreach (PropertyDef property in CardProperties) { PropertyDefValuePair newPropertyEntry = new PropertyDefValuePair() { Def = property }; try { - if (property.Type == PropertyType.StringEnumList) - { - string listValue = string.Empty; - foreach (JToken jToken in cardJToken[property.Name]) - { - if (!string.IsNullOrEmpty(listValue)) - listValue += EnumDef.Delimiter; - listValue += jToken.Value() ?? string.Empty; - } - newPropertyEntry.Value = listValue; - } - else if (property.Type == PropertyType.EscapedString) + string listValue = string.Empty; + JObject jObject = null; + switch (property.Type) { - newPropertyEntry.Value = (cardJToken.Value(property.Name) ?? string.Empty).Replace("\\", ""); - } - else - { - newPropertyEntry.Value = cardJToken.Value(property.Name) ?? string.Empty; + case PropertyType.ObjectEnumList: + listValue = string.Empty; + foreach (JToken jToken in cardJToken[property.Name]) + { + if (!string.IsNullOrEmpty(listValue)) + listValue += EnumDef.Delimiter; + jObject = jToken as JObject; + listValue += jObject?.Value("id") ?? string.Empty; + } + newPropertyEntry.Value = listValue; + break; + case PropertyType.ObjectList: + listValue = string.Empty; + foreach (JToken jToken in cardJToken[property.Name]) + { + if (!string.IsNullOrEmpty(listValue)) + listValue += EnumDef.Delimiter; + jObject = jToken as JObject; + listValue += jObject?.ToString() ?? string.Empty; + } + newPropertyEntry.Value = listValue; + break; + case PropertyType.ObjectEnum: + jObject = cardJToken[property.Name] as JObject; + newPropertyEntry.Value = jObject.Value("id") ?? string.Empty; + break; + case PropertyType.Object: + jObject = cardJToken[property.Name] as JObject; + newPropertyEntry.Value = jObject?.ToString() ?? string.Empty; + break; + case PropertyType.StringEnumList: + case PropertyType.StringList: + listValue = string.Empty; + foreach (JToken jToken in cardJToken[property.Name]) + { + if (!string.IsNullOrEmpty(listValue)) + listValue += EnumDef.Delimiter; + listValue += jToken.Value() ?? string.Empty; + } + newPropertyEntry.Value = listValue; + break; + case PropertyType.EscapedString: + newPropertyEntry.Value = (cardJToken.Value(property.Name) ?? string.Empty).Replace("\\", ""); + break; + case PropertyType.StringEnum: + case PropertyType.Number: + case PropertyType.Integer: + case PropertyType.Boolean: + case PropertyType.String: + default: + newPropertyEntry.Value = cardJToken.Value(property.Name) ?? string.Empty; + break; } } catch @@ -348,15 +400,29 @@ public void LoadCardFromJToken(JToken cardJToken, string defaultSetCode) cardProperties[property.Name] = newPropertyEntry; } - Card newCard = new Card(cardId, cardName, cardSet, cardProperties); - if (CardNames.Contains(cardName)) - newCard.IsReprint = true; + HashSet setCodes = new HashSet(); + if (ReprintsInCardObjectList) + { + foreach (JToken jToken in cardJToken[CardSetIdentifier]) + { + JObject setObject = jToken as JObject; + setCodes.Add(setObject?.Value(SetCodeIdentifier) ?? Set.DefaultCode); + } + } else - CardNames.Add(cardName); - LoadedCards[newCard.Id] = newCard; + setCodes.Add(cardJToken.Value(CardSetIdentifier) ?? defaultSetCode); - if (!Sets.ContainsKey(cardSet)) - LoadedSets[cardSet] = new Set(cardSet); + foreach(string cardSet in setCodes) + { + Card newCard = new Card(setCodes.Count > 1 ? (cardId + "_" + cardSet) : cardId, cardName, cardSet, cardProperties); + if (CardNames.Contains(cardName)) + newCard.IsReprint = true; + else + CardNames.Add(cardName); + LoadedCards[newCard.Id] = newCard; + if (!Sets.ContainsKey(cardSet)) + LoadedSets[cardSet] = new Set(cardSet); + } } public void LoadSetFromJToken(JToken setJToken, string defaultSetCode) diff --git a/Assets/Scripts/CardGameDef/PropertyDef.cs b/Assets/Scripts/CardGameDef/PropertyDef.cs index 8c49e0bf5..e53977290 100644 --- a/Assets/Scripts/CardGameDef/PropertyDef.cs +++ b/Assets/Scripts/CardGameDef/PropertyDef.cs @@ -5,12 +5,12 @@ namespace CardGameDef { public enum PropertyType { - Object, - EscapedString, String, - Number, - Integer, + EscapedString, Boolean, + Integer, + Number, + Object, StringEnum, StringList, StringEnumList, diff --git a/Assets/StreamingAssets/Standard Playing Cards/Standard Playing Cards.json b/Assets/StreamingAssets/Standard Playing Cards/Standard Playing Cards.json index ce4d32d86..7909b59dc 100644 --- a/Assets/StreamingAssets/Standard Playing Cards/Standard Playing Cards.json +++ b/Assets/StreamingAssets/Standard Playing Cards/Standard Playing Cards.json @@ -5,14 +5,17 @@ "cardImageUrl": "https://cardgamesim.finoldigital.com/games/Standard/sets/{cardSet}/{cardId}.{cardImageFileType}", "cardProperties": [{ "name": "rank", + "display": "Rank", "type": "stringEnum" }, { "name": "suit", + "display": "Suit", "type": "stringEnum" }, { "name": "color", + "display": "Color", "type": "stringEnum" } ], diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 6e7e2d976..bd131f47c 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -37,6 +37,7 @@ GraphicsSettings: - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 16002, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset index ef069fe65..a01835f4a 100644 --- a/ProjectSettings/InputManager.asset +++ b/ProjectSettings/InputManager.asset @@ -27,8 +27,8 @@ InputManager: descriptiveNegativeName: negativeButton: left positiveButton: right - altNegativeButton: - altPositiveButton: + altNegativeButton: a + altPositiveButton: d gravity: 3 dead: 0.001 sensitivity: 3 @@ -181,22 +181,6 @@ InputManager: type: 0 axis: 0 joyNum: 0 - - serializedVersion: 3 - m_Name: Draw - descriptiveName: - descriptiveNegativeName: - negativeButton: - positiveButton: d - altNegativeButton: - altPositiveButton: - gravity: 1000 - dead: 0.001 - sensitivity: 1000 - snap: 0 - invert: 0 - type: 0 - axis: 0 - joyNum: 0 - serializedVersion: 3 m_Name: FocusName descriptiveName: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 1fc6b6bd2..5176bf661 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -119,7 +119,7 @@ PlayerSettings: 16:10: 1 16:9: 1 Others: 0 - bundleVersion: 1.1.1 + bundleVersion: 1.2.0 preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0 @@ -158,7 +158,7 @@ PlayerSettings: buildNumber: Standalone: 0 iOS: 0 - AndroidBundleVersionCode: 40 + AndroidBundleVersionCode: 41 AndroidMinSdkVersion: 16 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 0 @@ -774,7 +774,7 @@ PlayerSettings: m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: CardGameSimulator - metroPackageVersion: 1.1.1.0 + metroPackageVersion: 1.2.0.0 metroCertificatePath: Assets\WSATestCertificate.pfx metroCertificatePassword: metroCertificateSubject: Finol Digital LLC diff --git a/docs/games/Dominoes/Dominoes.json b/docs/games/Dominoes/Dominoes.json index 0266e99c5..36a247be9 100644 --- a/docs/games/Dominoes/Dominoes.json +++ b/docs/games/Dominoes/Dominoes.json @@ -10,14 +10,17 @@ "cardPrimaryProperty": "suit", "cardProperties": [{ "name": "type", + "display": "Type", "type": "stringEnum" }, { "name": "suit", + "display": "Suit", "type": "stringEnum" }, { "name": "rank", + "display": "Rank", "type": "integer" } ], @@ -41,8 +44,8 @@ "enums": [{ "property": "type", "values": { - "0x1": "single", - "0x2": "double" + "0x1": "Single", + "0x2": "Double" } }, { diff --git a/docs/games/Hearthstone.json b/docs/games/Hearthstone.json index 187d428a9..1c11905cd 100644 --- a/docs/games/Hearthstone.json +++ b/docs/games/Hearthstone.json @@ -7,155 +7,346 @@ "cardImageUrl": "https://art.hearthstonejson.com/v1/render/latest/enUS/256x/{cardId}.{cardImageFileType}", "cardNameIsAtTop": false, "cardPrimaryProperty": "text", - "cardProperties": [ - {"name": "cost", "type": "integer" }, - {"name": "cardClass", "type": "enum" }, - {"name": "type", "type": "enum" }, - {"name": "faction", "type": "enum" }, - {"name": "race", "type": "enum" }, - {"name": "text", "type": "string" }, - {"name": "flavor", "type": "string" }, - {"name": "attack", "type": "integer" }, - {"name": "health", "type": "integer" }, - {"name": "durability", "type": "integer" }, - {"name": "armor", "type": "integer" }, - {"name": "rarity", "type": "enum" }, - {"name": "mechanics", "type": "enumList" }, - {"name": "howToEarn", "type": "string" }, - {"name": "howToEarnGolden", "type": "string" }, - {"name": "artist", "type": "string" }, - {"name": "dbfId", "type": "integer" } + "cardProperties": [{ + "name": "collectible", + "display": "Collectible as Player?", + "type": "boolean" + }, + { + "name": "cardClass", + "display": "Class", + "type": "stringEnum" + }, + { + "name": "cost", + "display": "Cost", + "type": "integer" + }, + { + "name": "rarity", + "display": "Rarity", + "type": "stringEnum" + }, + { + "name": "type", + "display": "Type", + "type": "stringEnum" + }, + { + "name": "faction", + "display": "Faction", + "type": "stringEnum", + "empty": "None" + }, + { + "name": "race", + "display": "Race", + "type": "stringEnum" + }, + { + "name": "text", + "display": "Card Text", + "type": "string" + }, + { + "name": "flavor", + "display": "Flavor Text", + "type": "string" + }, + { + "name": "attack", + "display": "Attack", + "type": "integer", + "empty": "N / A" + }, + { + "name": "health", + "display": "Health", + "type": "integer", + "empty": "N / A" + }, + { + "name": "durability", + "display": "Durability", + "type": "integer", + "empty": "N / A" + }, + { + "name": "armor", + "display": "Armor", + "type": "integer", + "empty": "N / A" + }, + { + "name": "hideStats", + "display": "Should Hide Stats?", + "type": "boolean" + }, + { + "name": "mechanics", + "display": "Mechanics", + "type": "stringEnumList" + }, + { + "name": "entourage", + "display": "Entourage", + "type": "stringList" + }, + { + "name": "playRequirements", + "display": "Play Requirements", + "type": "object" + }, + { + "name": "howToEarn", + "display": "How To Earn", + "type": "string" + }, + { + "name": "howToEarnGolden", + "display": "How To Earn Golden", + "type": "string" + }, + { + "name": "targetingArrowText", + "display": "Targetting Arrow Text", + "type": "string" + }, + { + "name": "artist", + "display": "Artist", + "type": "string" + }, + { + "name": "dbfId", + "type": "integer" + } ], - "cardSize": { "x": 2.55, "y": 3.8 }, + "cardSize": { + "x": 2.55, + "y": 3.8 + }, "deckFileType": "hsd", "deckMaxCount": 31, - "enums": [ - {"property": "rarity", "values": { - "COMMON": "COMMON", - "FREE": "FREE", - "RARE": "RARE", - "EPIC": "EPIC", - "LEGENDARY": "LEGENDARY" - }}, - {"property": "faction", "values": { - "HORDE": "HORDE", - "ALLIANCE": "ALLIANCE", - "NEUTRAL": "NEUTRAL" - }}, - {"property": "cardClass", "values": { - "DEATHKNIGHT": "DEATHKNIGHT", - "DRUID": "DRUID", - "HUNTER": "HUNTER", - "MAGE": "MAGE", - "PALADIN": "PALADIN", - "PRIEST": "PRIEST", - "ROGUE": "ROGUE", - "SHAMAN": "SHAMAN", - "WARLOCK": "WARLOCK", - "WARRIOR": "WARRIOR", - "DREAM": "DREAM", - "NEUTRAL": "NEUTRAL" - }}, - {"property": "type", "values": { - "GAME": "GAME", - "PLAYER": "PLAYER", - "MINION": "MINION", - "SPELL": "SPELL", - "ENCHANTMENT": "ENCHANTMENT", - "WEAPON": "WEAPON", - "ITEM": "ITEM", - "TOKEN": "TOKEN", - "HERO_POWER": "HERO_POWER" - }}, - {"property": "race", "values": { - "BLOODELF": "BLOODELF", - "DRAENEI": "DRAENEI", - "DWARF": "DWARF", - "GNOME": "GNOME", - "GOBLIN": "GOBLIN", - "HUMAN": "HUMAN", - "NIGHTELF": "NIGHTELF", - "ORC": "ORC", - "TAUREN": "TAUREN", - "TROLL": "TROLL", - "UNDEAD": "UNDEAD", - "WORGEN": "WORGEN", - "GOBLIN2": "GOBLIN2", - "MURLOC": "MURLOC", - "DEMON": "DEMON", - "SCOURGE": "SCOURGE", - "MECHANICAL": "MECHANICAL", - "ELEMENTAL": "ELEMENTAL", - "OGRE": "OGRE", - "BEAST": "BEAST", - "TOTEM": "TOTEM", - "NERUBIAN": "NERUBIAN", - "PIRATE": "PIRATE", - "DRAGON": "DRAGON" - }}, - {"property": "mechanics", "values": { - "ADJACENT_BUFF": "ADJACENT_BUFF", - "AI_MUST_PLAY": "AI_MUST_PLAY", - "APPEAR_FUNCTIONALLY_DEAD": "APPEAR_FUNCTIONALLY_DEAD", - "ADAPT": "ADAPT", - "AURA": "AURA", - "BATTLECRY": "BATTLECRY", - "CANT_ATTACK": "CANT_ATTACK", - "CANT_BE_TARGETED_BY_ABILITIES": "CANT_BE_TARGETED_BY_ABILITIES", - "CANT_BE_TARGETED_BY_HERO_POWERS": "CANT_BE_TARGETED_BY_HERO_POWERS", - "CHARGE": "CHARGE", - "CHOOSE_ONE": "CHOOSE_ONE", - "COMBO": "COMBO", - "COUNTER": "COUNTER", - "DEATHRATTLE": "DEATHRATTLE", - "DISCOVER": "DISCOVER", - "DIVINE_SHIELD": "DIVINE_SHIELD", - "ENRAGED": "ENRAGED", - "EVIL_GLOW": "EVIL_GLOW", - "FORGETFUL": "FORGETFUL", - "FREEZE": "FREEZE", - "IMMUNE": "IMMUNE", - "INSPIRE": "INSPIRE", - "JADE_GOLEM": "JADE_GOLEM", - "MORPH": "MORPH", - "POISONOUS": "POISONOUS", - "QUEST": "QUEST", - "RECEIVES_DOUBLE_SPELLDAMAGE_BONUS": "RECEIVES_DOUBLE_SPELLDAMAGE_BONUS", - "RITUAL": "RITUAL", - "SECRET": "SECRET", - "SILENCE": "SILENCE", - "STEALTH": "STEALTH", - "TAG_ONE_TURN_EFFECT": "TAG_ONE_TURN_EFFECT", - "TAUNT": "TAUNT", - "TOPDECK": "TOPDECK", - "UNTOUCHABLE": "UNTOUCHABLE", - "WINDFURY": "WINDFURY", - "ImmuneToSpellpower": "ImmuneToSpellpower", - "InvisibleDeathrattle": "InvisibleDeathrattle" - }} + "enums": [{ + "property": "cardClass", + "values": { + "DEATHKNIGHT": "Death-Knight", + "DRUID": "Druid", + "HUNTER": "Hunter", + "MAGE": "Mage", + "PALADIN": "Paladin", + "PRIEST": "Priest", + "ROGUE": "Rogue", + "SHAMAN": "Shaman", + "WARLOCK": "Warlock", + "WARRIOR": "Warrior", + "DREAM": "Dream", + "NEUTRAL": "Neutral" + } + }, + { + "property": "rarity", + "values": { + "COMMON": "Common", + "FREE": "Free", + "RARE": "Rare", + "EPIC": "Epic", + "LEGENDARY": "Legendary" + } + }, + { + "property": "type", + "values": { + "GAME": "Game", + "PLAYER": "Player", + "MINION": "Minion", + "SPELL": "Spell", + "ENCHANTMENT": "Enchantment", + "WEAPON": "Weapon", + "ITEM": "Item", + "TOKEN": "Token", + "HERO_POWER": "Hero Power" + } + }, + { + "property": "faction", + "values": { + "HORDE": "Horde", + "ALLIANCE": "Alliance", + "NEUTRAL": "Neutral" + } + }, + { + "property": "race", + "values": { + "BLOODELF": "Blood Elf", + "DRAENEI": "Draenei", + "DWARF": "Dwarf", + "GNOME": "Gnome", + "GOBLIN": "Goblin", + "HUMAN": "Human", + "NIGHTELF": "Night Elf", + "ORC": "Orc", + "TAUREN": "Tauren", + "TROLL": "Troll", + "UNDEAD": "Undead", + "WORGEN": "Worgen", + "GOBLIN2": "Goblin2", + "MURLOC": "Murloc", + "DEMON": "Demon", + "SCOURGE": "Scourge", + "MECHANICAL": "Mechanical", + "ELEMENTAL": "Elemental", + "OGRE": "Ogre", + "BEAST": "Beast", + "TOTEM": "Totem", + "NERUBIAN": "Nerubian", + "PIRATE": "Pirate", + "DRAGON": "Dragon" + } + }, + { + "property": "mechanics", + "values": { + "ADJACENT_BUFF": "ADJACENT_BUFF", + "AI_MUST_PLAY": "AI_MUST_PLAY", + "APPEAR_FUNCTIONALLY_DEAD": "APPEAR_FUNCTIONALLY_DEAD", + "ADAPT": "ADAPT", + "AURA": "AURA", + "BATTLECRY": "BATTLECRY", + "CANT_ATTACK": "CANT_ATTACK", + "CANT_BE_TARGETED_BY_ABILITIES": "CANT_BE_TARGETED_BY_ABILITIES", + "CANT_BE_TARGETED_BY_HERO_POWERS": "CANT_BE_TARGETED_BY_HERO_POWERS", + "CHARGE": "CHARGE", + "CHOOSE_ONE": "CHOOSE_ONE", + "COMBO": "COMBO", + "COUNTER": "COUNTER", + "DEATHRATTLE": "DEATHRATTLE", + "DISCOVER": "DISCOVER", + "DIVINE_SHIELD": "DIVINE_SHIELD", + "ENRAGED": "ENRAGED", + "EVIL_GLOW": "EVIL_GLOW", + "FORGETFUL": "FORGETFUL", + "FREEZE": "FREEZE", + "IMMUNE": "IMMUNE", + "INSPIRE": "INSPIRE", + "JADE_GOLEM": "JADE_GOLEM", + "MORPH": "MORPH", + "POISONOUS": "POISONOUS", + "QUEST": "QUEST", + "RECEIVES_DOUBLE_SPELLDAMAGE_BONUS": "RECEIVES_DOUBLE_SPELLDAMAGE_BONUS", + "RITUAL": "RITUAL", + "SECRET": "SECRET", + "SILENCE": "SILENCE", + "STEALTH": "STEALTH", + "TAG_ONE_TURN_EFFECT": "TAG_ONE_TURN_EFFECT", + "TAUNT": "TAUNT", + "TOPDECK": "TOPDECK", + "UNTOUCHABLE": "UNTOUCHABLE", + "WINDFURY": "WINDFURY", + "ImmuneToSpellpower": "ImmuneToSpellpower", + "InvisibleDeathrattle": "InvisibleDeathrattle" + } + } ], - "extras": [ - {"group": "Hero", "property": "dbfId", "value": "7" }, - {"group": "Hero", "property": "dbfId", "value": "31" }, - {"group": "Hero", "property": "dbfId", "value": "274" }, - {"group": "Hero", "property": "dbfId", "value": "637" }, - {"group": "Hero", "property": "dbfId", "value": "671" }, - {"group": "Hero", "property": "dbfId", "value": "813" }, - {"group": "Hero", "property": "dbfId", "value": "893" }, - {"group": "Hero", "property": "dbfId", "value": "930" }, - {"group": "Hero", "property": "dbfId", "value": "1066" }, - {"group": "Hero", "property": "dbfId", "value": "2826" }, - {"group": "Hero", "property": "dbfId", "value": "2827" }, - {"group": "Hero", "property": "dbfId", "value": "2828" }, - {"group": "Hero", "property": "dbfId", "value": "2829" }, - {"group": "Hero", "property": "dbfId", "value": "39117" }, - {"group": "Hero", "property": "dbfId", "value": "40183" }, - {"group": "Hero", "property": "dbfId", "value": "40195" }, - {"group": "Hero", "property": "dbfId", "value": "46116" }, - {"group": "Hero", "property": "dbfId", "value": "47817" }, - {"group": "Hero", "property": "dbfId", "value": "41887" } + "extras": [{ + "group": "Hero", + "property": "dbfId", + "value": "7" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "31" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "274" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "637" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "671" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "813" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "893" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "930" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "1066" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "2826" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "2827" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "2828" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "2829" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "39117" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "40183" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "40195" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "46116" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "47817" + }, + { + "group": "Hero", + "property": "dbfId", + "value": "41887" + } ], "gameStartHandCount": 3, "gameStartPointsCount": 30, "name": "Hearthstone" -} +} \ No newline at end of file diff --git a/docs/games/Mahjong/Mahjong.json b/docs/games/Mahjong/Mahjong.json index e69563164..a72f37643 100644 --- a/docs/games/Mahjong/Mahjong.json +++ b/docs/games/Mahjong/Mahjong.json @@ -9,14 +9,17 @@ "cardPrimaryProperty": "type", "cardProperties": [{ "name": "type", + "display": "Type", "type": "stringEnum" }, { "name": "suit", + "display": "Suit", "type": "stringEnum" }, { "name": "rank", + "display": "Rank", "type": "string" } ], @@ -28,21 +31,21 @@ "enums": [{ "property": "type", "values": { - "simple": "simple", - "honor": "honor", - "bonus": "bonus" + "simple": "Simple", + "honor": "Honor", + "bonus": "Bonus" } }, { "property": "suit", "values": { - "circle": "circle", - "bamboo": "bamboo", - "character": "character", - "wind": "wind", - "dragon": "dragon", - "flower": "flower", - "season": "season" + "circle": "Circle", + "bamboo": "Bamboo", + "character": "Character", + "wind": "Wind", + "dragon": "Dragon", + "flower": "Flower", + "season": "Season" } } ], diff --git a/docs/games/Standard/Standard.json b/docs/games/Standard/Standard.json index ce4d32d86..7909b59dc 100644 --- a/docs/games/Standard/Standard.json +++ b/docs/games/Standard/Standard.json @@ -5,14 +5,17 @@ "cardImageUrl": "https://cardgamesim.finoldigital.com/games/Standard/sets/{cardSet}/{cardId}.{cardImageFileType}", "cardProperties": [{ "name": "rank", + "display": "Rank", "type": "stringEnum" }, { "name": "suit", + "display": "Suit", "type": "stringEnum" }, { "name": "color", + "display": "Color", "type": "stringEnum" } ], diff --git a/docs/pages/custom.md b/docs/pages/custom.md index 288615864..43b796641 100644 --- a/docs/pages/custom.md +++ b/docs/pages/custom.md @@ -8,7 +8,7 @@ Card Game Simulator allows users to [download custom card games to use within th ## CGS games directory Custom games are defined by creating a new folder within the persistent games data directory. The location of this persistent data directory varies depending on platform. Some examples include: - Android: /Data/Data/com.finoldigital.cardgamesim/files/games/ -- Windows: C:/Users/\/AppData/LocalLow/Finol Digital LLC/Card Game Simulator/games/ +- Universal Windows Platform: C:\Users\\AppData\Local\Packages\CardGameSimulator_nvq7k659m756y\LocalState - Mac: ~/Library/Application Support/Finol Digital LLC/Card Game Simulator/games/ ## Custom game folder structure @@ -32,7 +32,9 @@ The structure of this custom game folder is: * ... ## JSON File Structure -When downloading a custom game from a url, the data that is being downloaded is the contents of the \.json file. CGS generates the rest of the folder structure based off the information in that file. You can create your own json and validate against these schema: +When downloading a custom game from a url, the data that is being downloaded is the contents of the \.json file. CGS generates the rest of the folder structure based off the information in that file. + +You can create your own json and validate against these schema: - [CardGameDef](schema/CardGameDef.json) - [AllCards](schema/AllCards.json) - [AllSets](schema/AllSets.json) diff --git a/docs/pages/keyboard.md b/docs/pages/keyboard.md index 6e867f9ac..f7b75037d 100644 --- a/docs/pages/keyboard.md +++ b/docs/pages/keyboard.md @@ -7,48 +7,48 @@ If [your CGS device](index.html#play-anywhere) has a keyboard, you can use these ## Main Menu - **Cancel**: *Esc* - Exit CGS. -- **Horizontal**: *left*, *right* - Scroll through card games. -- **Vertical**: *down*, *up* - Scroll through main menu options. +- **Horizontal**: *left*, *right* - Select previous/next card game. +- **Vertical**: *down*, *up* - Scroll through Main Menu buttons. - **Sort**: *q* - Brings up the Game Selection Menu. - **New**: *e* - Start Game. - **Load**: *r* - Join Game. - **Save**: *t* - Edit Deck. -- **Filter**: *f* - Brings up the options menu. +- **Filter**: *f* - Brings up the Options Menu. - **Submit**: *Enter* - Click on selected button. ## Play Mode -- **Cancel**: *Esc* - Back to main menu. -- **Load**: *r* - Brings up the deck load menu. -- **Filter**: *f* - Brings up the search filter menu. -- **Sort**: *q* - Brings up the dice menu. -- **Draw**: *d* - Draw a card from your deck to your hand. +- **Cancel**: *Esc* - Back to Main Menu. +- **Load**: *r* - Brings up the Deck Load Menu. +- **Save**: *q* - Brings up the Dice Menu. +- **Filter**: *f* - Brings up the Card Search/Filter Menu. +- **Horizontal**: *left*, *right* - Move the top card of the deck. Left to discard, Right to hand. ## Card Viewer -- **Cancel**: *Esc* - Hide the card viewer. -- **CardViewer**: *c*, *v* - Scroll through properties in the card viewer. +- **Cancel**: *Esc* - Hide the Card Viewer. +- **CardViewer**: *c*, *v* - Scroll through properties in the Card Viewer. - **Submit**: *Enter* - Double-click on selected card. ## Deck Editor -- **Cancel**: *Esc* - Back to main menu. -- **Vertical**: *down*, *up* - Scroll through the deck editor. -- **Horizontal**: *left*, *right* - Scroll through search results. +- **Cancel**: *Esc* - Back to Main Menu. +- **Vertical**: *down*, *up* - Scroll through cards in the deck editor. +- **Horizontal**: *left*, *right* - Scroll through cards in the search results. - **Page**: *PgUp*, *PgDn* - Page through search results. - **Column**: *home*, *end* - Shift through stacks in the deck editor. -- **Sort**: *q* - Brings up the sort menu. +- **Sort**: *q* - Sorts the deck editor. - **New**: *e* - Clears the deck editor. -- **Load**: *r* - Brings up the deck load menu. -- **Save**: *t* - Brings up the deck save menu. -- **Filter**: *f* - Brings up the search filter menu. +- **Load**: *r* - Brings up the Deck Load Menu. +- **Save**: *t* - Brings up the Deck Save Menu. +- **Filter**: *f* - Brings up the Card Search/Filter Menu. - **FocusName**: *\`* - Focuses keyboard to the search name input field. ## Options Menu -- **Cancel**: *Esc* - Back to main menu. +- **Cancel**: *Esc* - Back to Main Menu. - **Vertical**: *down*, *up* - Scroll through options. - **Sort**: *q* - Link to view online rules. - **New**: *e* - Link to the CGS website. - **Load**: *r* - Link to this webpage. - **Save**: *t* - Email . -- **Submit**: *Enter* - Click on selected button. +- **Submit**: *Enter* - Click on selected option. ## Popup - **Cancel**: *Esc* - Cancel/Close. @@ -57,9 +57,10 @@ If [your CGS device](index.html#play-anywhere) has a keyboard, you can use these ## Game Selection Menu - **Cancel**: *Esc* - Cancel. -- **Horizontal**: *left*, *right* - Scroll through card games. -- **Vertical**: *down*, *up* - Scroll through games. +- **Horizontal**: *left*, *right* - Select previous/next card game. +- **Vertical**: *down*, *up* - Scroll through card games. - **Page**: *PgUp*, *PgDn* - Move the scrollbar. +- **Sort**: *q* - Share selected card game. - **New**: *e* - Brings up or clears the download url input field. - **Load**: *r* - Brings up or clears the download url input field. - **Save**: *t* - Pastes clipboard into the url input field. @@ -91,6 +92,10 @@ If [your CGS device](index.html#play-anywhere) has a keyboard, you can use these - **Load**: *r* - Copies deck text to the text clipboard. - **Submit**: *Enter* - Save. +## Dice Menu +- **Cancel**: *Esc* - Cancel. +- **Submit**: *Enter* - Create dice. + ## Card Search/Filter Menu - **Cancel**: *Esc* - Cancel. - **FocusName**: *\`* - Focuses keyboard to the previous text input field. @@ -101,7 +106,3 @@ If [your CGS device](index.html#play-anywhere) has a keyboard, you can use these - **New**: *e* - Toggles selected enum value. - **Delete**: *Delete* - Clear. - **Submit**: *Enter* - Search! - -## Dice Menu -- **Cancel**: *Esc* - Cancel. -- **Submit**: *Enter* - Create dice. diff --git a/docs/pages/roadmap.md b/docs/pages/roadmap.md index 664d585c7..4bc7a7a2c 100644 --- a/docs/pages/roadmap.md +++ b/docs/pages/roadmap.md @@ -10,14 +10,6 @@ permalink: roadmap.html - Added support for different types of card metadata ## Current Sprint -- Instead of specifying page_num, add ability to find it from json response -- Support boolean card property data type -- Rename to stringEnum -- Support string list card property data type -- Support object card property data type -- Support object enum card property data type -- Support object list card property data type -- Support object enum list card property data type - Fix: NetworkDiscovery error on iOS sleep - Release v1 to the App Store - Release v1 to the Mac App Store @@ -52,7 +44,10 @@ permalink: roadmap.html - Consider keyboard shortcuts ## Icebox +- Add rate limit for how often to update allCards and allSets - Support Number card property data type (decimals) +- Enhace boolean card property data type +- Add identifiers for object card property data types - Support custom card backgrounds (Hearthstone) - Support multiple card backs - Support more than 1 card face diff --git a/docs/schema/CardGameDef.json b/docs/schema/CardGameDef.json index 00d8f7ad1..60a0dafe4 100644 --- a/docs/schema/CardGameDef.json +++ b/docs/schema/CardGameDef.json @@ -23,17 +23,21 @@ "format": "uri" }, "allCardsUrlPageCount": { - "description": "When downloading AllCards.json from allCardsUrl, CGS will use ++ for each page after the first page.", + "description": "If allCardsUrlPageCount > 1, CGS will download ++ for each page.", "default": 1, "type": "integer" }, "allCardsUrlPageCountIdentifier": { - "description": "When downloading AllCards.json from allCardsUrl, if is not empty, CGS will set allCardsUrlPageCount to the response value of from .", - "default": 1, + "description": "If allCardsUrlPageCountIdentifier is set, CGS will set the allCardsUrlPageCount to the response value of from .", "type": "string" }, + "allCardsUrlPageCountDivisor": { + "description": "allCardsUrlPageCountDivisor can be set to the # of cards per page, ie: allCardsUrlPageCount = /. ", + "default": 1, + "type": "integer" + }, "allCardsUrlPageIdentifier": { - "description": "If allCardsUrlPageCount > 1, CGS will use ++ for each page after the first page.", + "description": "If allCardsUrlPageCount > 1, CGS will download ++ for each page.", "default": "?page=", "type": "string" }, @@ -97,9 +101,9 @@ "default": "png", "type": "string" }, - "cardImageUrl": { + "cardImageProperty": { "description": "cardImageProperty is the *Card:Property* which points to the image for this card. If is empty, will be used instead.", - "type": "string", + "type": "string" }, "cardImageUrl": { "description": "cardImageUrl indicates a parameterized url from which CGS downloads missing card image files. Parameters: {cardId}=*Card:Id*, {cardName}=*Card:Name*, {cardSet}=*Card:SetCode*, {card.}=*Card:*, {cardImageFileType}=", @@ -326,6 +330,10 @@ "default": { "x": 23.5, "y": 20.25 }, "$ref": "#/definitions/vector2" }, + "reprintsInCardObjectList": { + "description": "If reprintsInCardObjectList is set to true, each card will be duplicated with each set in the object list at . The objects should have id=setCode", + "type": "boolean" + }, "rulesUrl": { "description": "rulesUrl should link to this game's online rulebook. This link is accessed in CGS by Main Menu -> Options -> View Online Rules.", "type": "string",