界面上无法识别,提示是

[Unidentified card ID :DAL_010]
[Unidentified card ID :DAL_415]

Unidentified card ID :HERO_02c

首先使用卡牌工具,查询卡牌id对应的卡牌名字

https://github.com/ChuckHearthstone/CardQuery

1.添加卡牌id的枚举

https://github.com/ChuckHearthstone/SilverFish/blob/89ca9e06327f1bd4271c5ebb2ece268530fc194e/DefaultRoutine/Chuck.SilverFish/Enums/CardIdEnum.cs#L1184

2.添加卡牌的Sim

最新的处理方案是,直接引用第三方的类库来做卡牌的数据解析

https://www.nuget.org/packages/Chuck-HearthDb/   HearthBuddy的exe文件,引用这个类库

然后修改卡牌代码的解析 https://github.com/ChuckHearthstone/SilverFish/blob/master/DefaultRoutine/Chuck.SilverFish/ai/CardDB.cs#L137

  1. private CardDB()
  2. {
  3. CardList.Clear();
  4. cardidToCardList.Clear();
  5.  
  6. //placeholdercard
  7. Card plchldr = new Card {name = CardName.unknown, cost = };
  8. namelist.Add("unknown");
  9. CardList.Add(plchldr);
  10. unknownCard = CardList[];
  11.  
  12. string name = "";
  13. var cards = Cards.All;
  14. foreach (var item in cards.Keys)
  15. {
  16. var card = new Card();
  17. allCardIDS.Add(item);
  18. card.cardIDenum = ConvertHelper.cardIdstringToEnum(item);
  19. var dbCard = cards[item];
  20. card.EnglishName = dbCard.GetLocName(Locale.enUS);
  21. card.ChineseName = dbCard.GetLocName(Locale.zhCN);
  22. card.Health = dbCard.Health;
  23. card.Class = (int) dbCard.Class;
  24. card.Attack.Value = dbCard.Attack;
  25. card.race = (int) dbCard.Race;
  26. card.rarity = (int) dbCard.Rarity;
  27. card.cost = dbCard.Cost;
  28. card.type = (CardType) dbCard.Type;
  29. if (card.type == CardType.Token)
  30. {
  31. card.isToken = true;
  32. }
  33. if (card.type == CardType.ENCHANTMENT)
  34. {
  35. continue;
  36. }
  37.  
  38. var trimmedCardName = TrimHelper.TrimEnglishName(dbCard.Name);
  39. if (!string.IsNullOrWhiteSpace(name))
  40. {
  41. namelist.Add(trimmedCardName);
  42. }
  43. card.name = ConvertHelper.cardNamestringToEnum(trimmedCardName);
  44.  
  45. card.poisonous = dbCard.Entity.GetTag(GameTag.POISONOUS) == ;
  46. card.Enrage = dbCard.Entity.GetTag(GameTag.ENRAGED) == ;
  47. card.Aura = dbCard.Entity.GetTag(GameTag.AURA) == ;
  48. card.tank = dbCard.Entity.GetTag(GameTag.TAUNT) == ;
  49. card.battlecry= dbCard.Entity.GetTag(GameTag.BATTLECRY) == ;
  50. card.discover = dbCard.Entity.GetTag(GameTag.DISCOVER) == ;
  51. card.windfury = dbCard.Entity.GetTag(GameTag.WINDFURY) == ;
  52. card.deathrattle = dbCard.Entity.GetTag(GameTag.DEATHRATTLE) == ;
  53. card.Reborn = dbCard.Entity.GetTag(GameTag.REBORN) == ;
  54. card.Inspire = dbCard.Entity.GetTag(GameTag.INSPIRE) == ;
  55. card.Durability = dbCard.Entity.GetTag(GameTag.DURABILITY);
  56. card.Elite = dbCard.Entity.GetTag(GameTag.ELITE) == ;
  57. card.Combo = dbCard.Entity.GetTag(GameTag.COMBO) == ;
  58. card.oneTurnEffect = dbCard.Entity.GetTag(GameTag.TAG_ONE_TURN_EFFECT) == ;
  59. card.overload = dbCard.Entity.GetTag(GameTag.OVERLOAD);
  60. card.lifesteal = dbCard.Entity.GetTag(GameTag.LIFESTEAL) == ;
  61. card.untouchable = dbCard.Entity.GetTag(GameTag.UNTOUCHABLE) == ;
  62. card.Stealth = dbCard.Entity.GetTag(GameTag.STEALTH)==;
  63. card.Secret = dbCard.Entity.GetTag(GameTag.SECRET) == ;
  64. card.Quest = dbCard.Entity.GetTag(GameTag.QUEST) == ;
  65. card.Freeze = dbCard.Entity.GetTag(GameTag.FREEZE) == ;
  66. card.AdjacentBuff = dbCard.Entity.GetTag(GameTag.ADJACENT_BUFF) == ;
  67. card.DivineShield = dbCard.Entity.GetTag(GameTag.DIVINE_SHIELD) == ;
  68. card.Charge = dbCard.Entity.GetTag(GameTag.CHARGE) == ;
  69. card.Rush.Value = dbCard.Entity.GetTag(GameTag.RUSH) == ;
  70. card.Silence = dbCard.Entity.GetTag(GameTag.SILENCE) == ;
  71. card.Morph = dbCard.Entity.GetTag(GameTag.MORPH) == ;
  72. card.Spellpower = dbCard.Entity.GetTag(GameTag.SPELLPOWER) > ;
  73. card.spellpowervalue = dbCard.Entity.GetTag(GameTag.SPELLPOWER);
  74. if (!string.IsNullOrEmpty(dbCard.Text))
  75. {
  76. if (dbCard.Text.ToLower().Contains("choose one"))
  77. {
  78. card.choice = true;
  79. }
  80. }
  81.  
  82. var playRequirements = dbCard.Entity.GetPlayRequirements();
  83. if (playRequirements != null)
  84. {
  85. foreach (var playRequirement in playRequirements)
  86. {
  87. var reqId = Convert.ToInt32(playRequirement.ReqId);
  88. var errorType = (ErrorType) Enum.ToObject(typeof(ErrorType), reqId);
  89. card.playrequires.Add(errorType);
  90. }
  91. }
  92.  
  93. if (card.name != CardName.unknown)
  94. {
  95. CardList.Add(card);
  96. if (!cardidToCardList.ContainsKey(card.cardIDenum))
  97. {
  98. cardidToCardList.Add(card.cardIDenum, card);
  99. }
  100. else
  101. {
  102. Logger.GetLoggerInstanceForType()
  103. .ErrorFormat("[c.cardIDenum:" + card.cardIDenum + "] already exists in cardidToCardList");
  104. }
  105. }
  106. }
  107.  
  108. teacherminion = getCardDataFromID(CardIdEnum.NEW1_026t);
  109. illidanminion = getCardDataFromID(CardIdEnum.EX1_614t);
  110. lepergnome = getCardDataFromID(CardIdEnum.EX1_029);
  111. burlyrockjaw = getCardDataFromID(CardIdEnum.GVG_068);
  112.  
  113. Helpfunctions.Instance.InfoLog("CardList:" + cardidToCardList.Count);
  114.  
  115. }

分析(淘汰)

搜索getcardid,在所有的相关函数处设置断点,看会进入哪里的断点

发现是进入了namespace Triton.Game.Mapping

[Attribute38("EntityBase")]
public class EntityBase : MonoClass

这个类

  1. public string GetCardId()
  2. {
  3. return base.method_13("GetCardId", Array.Empty<object>());
  4. }

namespace Triton.Game

public class HSCard

  1. public string Id
  2. {
  3. get
  4. {
  5. return this.Entity_0.GetCardId();
  6. }
  7. }

namespace HREngine.Bots

public class Silverfish

  1. // HREngine.Bots.Silverfish
  2. // Token: 0x06000048 RID: 72 RVA: 0x0000A16C File Offset: 0x0000836C
  3. private void getDecks()
  4. {
  5. Dictionary<string, int> tmpDeck = new Dictionary<string, int>(this.startDeck);
  6. List<GraveYardItem> graveYard = new List<GraveYardItem>();
  7. Dictionary<CardDB.cardIDEnum, int> og = new Dictionary<CardDB.cardIDEnum, int>();
  8. Dictionary<CardDB.cardIDEnum, int> eg = new Dictionary<CardDB.cardIDEnum, int>();
  9. int owncontroler = TritonHs.OurHero.GetTag(GAME_TAG.CONTROLLER);
  10. int enemycontroler = TritonHs.EnemyHero.GetTag(GAME_TAG.CONTROLLER);
  11. this.turnDeck.Clear();
  12. this.noDuplicates = false;
  13. List<HSCard> allcards = TritonHs.GetAllCards();
  14. int allcardscount = allcards.Count;
  15. for (int i = ; i < allcardscount; i++)
  16. {
  17. HSCard entity = allcards[i];
  18. if (entity.Id != null && !(entity.Id == ""))
  19. {
  20. if (CardDB.Instance.cardIdstringToEnum(entity.Id) == CardDB.cardIDEnum.UNG_116t)
  21. {
  22. this.ownMinionsCost0 = true;
  23. }
  24. if (entity.GetZone() == TAG_ZONE.GRAVEYARD)
  25. {
  26. CardDB.cardIDEnum cide = CardDB.Instance.cardIdstringToEnum(entity.Id);
  27. GraveYardItem gyi = new GraveYardItem(cide, entity.EntityId, entity.GetTag(GAME_TAG.CONTROLLER) == owncontroler);
  28. graveYard.Add(gyi);
  29. if (entity.GetTag(GAME_TAG.CONTROLLER) == owncontroler)
  30. {
  31. if (og.ContainsKey(cide))
  32. {
  33. Dictionary<CardDB.cardIDEnum, int> dictionary;
  34. CardDB.cardIDEnum key;
  35. (dictionary = og)[key = cide] = dictionary[key] + ;
  36. }
  37. else
  38. {
  39. og.Add(cide, );
  40. }
  41. }
  42. else if (entity.GetTag(GAME_TAG.CONTROLLER) == enemycontroler)
  43. {
  44. if (eg.ContainsKey(cide))
  45. {
  46. Dictionary<CardDB.cardIDEnum, int> dictionary;
  47. CardDB.cardIDEnum key;
  48. (dictionary = eg)[key = cide] = dictionary[key] + ;
  49. }
  50. else
  51. {
  52. eg.Add(cide, );
  53. }
  54. }
  55. if (cide == CardDB.cardIDEnum.UNG_067t1)
  56. {
  57. this.ownCrystalCore = ;
  58. }
  59. }
  60. string entityId = entity.Id;
  61. TAG_ZONE entZone = entity.GetZone();
  62. if (i < )
  63. {
  64. if (entityId != "")
  65. {
  66. if (entZone != TAG_ZONE.DECK)
  67. {
  68. if (tmpDeck.ContainsKey(entityId))
  69. {
  70. Dictionary<string, int> dictionary2;
  71. string key2;
  72. (dictionary2 = tmpDeck)[key2 = entityId] = dictionary2[key2] - ;
  73. }
  74. }
  75. }
  76. }
  77. else if (i >= && entity.ControllerId == owncontroler)
  78. {
  79. if (this.extraDeck.ContainsKey(i))
  80. {
  81. if (entityId != "" && entityId != this.extraDeck[i].id)
  82. {
  83. this.extraDeck[i].setId(entityId);
  84. }
  85. if (entZone == TAG_ZONE.DECK != this.extraDeck[i].isindeck)
  86. {
  87. this.extraDeck[i].setisindeck(entZone == TAG_ZONE.DECK);
  88. }
  89. }
  90. else if (entZone == TAG_ZONE.DECK)
  91. {
  92. this.extraDeck.Add(i, new Silverfish.extraCard(entityId, true));
  93. }
  94. }
  95. }
  96. }
  97. Action a = Ai.Instance.bestmove;
  98. foreach (KeyValuePair<int, Silverfish.extraCard> c in this.extraDeck)
  99. {
  100. if (c.Value.isindeck)
  101. {
  102. string entityId = c.Value.id;
  103. if (entityId == "")
  104. {
  105. if (a != null)
  106. {
  107. actionEnum actionType = a.actionType;
  108. if (actionType == actionEnum.playcard)
  109. {
  110. CardDB.cardIDEnum cardIDEnum = a.card.card.cardIDenum;
  111. if (cardIDEnum <= CardDB.cardIDEnum.LOE_019t)
  112. {
  113. if (cardIDEnum == CardDB.cardIDEnum.BRM_007)
  114. {
  115. goto IL_42B;
  116. }
  117. if (cardIDEnum != CardDB.cardIDEnum.LOE_002)
  118. {
  119. if (cardIDEnum == CardDB.cardIDEnum.LOE_019t)
  120. {
  121. entityId = "LOE_019t2";
  122. }
  123. }
  124. else
  125. {
  126. entityId = "LOE_002t";
  127. }
  128. }
  129. else if (cardIDEnum != CardDB.cardIDEnum.LOE_079)
  130. {
  131. if (cardIDEnum == CardDB.cardIDEnum.LOE_104)
  132. {
  133. goto IL_42B;
  134. }
  135. if (cardIDEnum == CardDB.cardIDEnum.LOE_110)
  136. {
  137. entityId = "LOE_110t";
  138. }
  139. }
  140. else
  141. {
  142. entityId = "LOE_019t";
  143. }
  144. goto IL_485;
  145. IL_42B:
  146. if (a.target != null)
  147. {
  148. entityId = a.target.handcard.card.cardIDenum.ToString();
  149. }
  150. }
  151. IL_485:;
  152. }
  153. if (entityId == "")
  154. {
  155. Dictionary<CardDB.cardIDEnum, int> oldCardsOut = Probabilitymaker.Instance.enemyCardsOut;
  156. foreach (KeyValuePair<CardDB.cardIDEnum, int> tmp in eg)
  157. {
  158. if (!oldCardsOut.ContainsKey(tmp.Key) || tmp.Value != oldCardsOut[tmp.Key])
  159. {
  160. CardDB.cardIDEnum cardIDEnum = tmp.Key;
  161. if (cardIDEnum != CardDB.cardIDEnum.AT_035)
  162. {
  163. if (cardIDEnum != CardDB.cardIDEnum.GVG_031)
  164. {
  165. if (cardIDEnum == CardDB.cardIDEnum.LOE_111)
  166. {
  167. entityId = "LOE_111";
  168. }
  169. }
  170. else
  171. {
  172. entityId = "aiextra1";
  173. }
  174. }
  175. else
  176. {
  177. entityId = "AT_035t";
  178. }
  179. }
  180. }
  181. if (entityId == "" && this.lastpf != null)
  182. {
  183. int num = ;
  184. foreach (Minion j in this.enemyMinions)
  185. {
  186. if (j.handcard.card.cardIDenum == CardDB.cardIDEnum.GVG_056)
  187. {
  188. num++;
  189. }
  190. }
  191. if (num > )
  192. {
  193. foreach (Minion j in this.lastpf.enemyMinions)
  194. {
  195. if (j.handcard.card.cardIDenum == CardDB.cardIDEnum.GVG_056)
  196. {
  197. num--;
  198. }
  199. }
  200. }
  201. if (num > )
  202. {
  203. entityId = "GVG_056t";
  204. }
  205. else
  206. {
  207. num = ;
  208. foreach (Minion j in this.lastpf.ownMinions)
  209. {
  210. if (j.handcard.card.cardIDenum == CardDB.cardIDEnum.GVG_035)
  211. {
  212. num++;
  213. }
  214. }
  215. if (num > )
  216. {
  217. foreach (Minion j in this.ownMinions)
  218. {
  219. if (j.handcard.card.cardIDenum == CardDB.cardIDEnum.GVG_035)
  220. {
  221. num--;
  222. }
  223. }
  224. }
  225. if (num > )
  226. {
  227. entityId = "GVG_035";
  228. }
  229. }
  230. }
  231. }
  232. if (entityId == "")
  233. {
  234. entityId = "aiextra1";
  235. }
  236. }
  237. c.Value.setId(entityId);
  238. CardDB.cardIDEnum ce = CardDB.Instance.cardIdstringToEnum(entityId);
  239. if (this.turnDeck.ContainsKey(ce))
  240. {
  241. Dictionary<CardDB.cardIDEnum, int> dictionary;
  242. CardDB.cardIDEnum key;
  243. (dictionary = this.turnDeck)[key = ce] = dictionary[key] + ;
  244. }
  245. else
  246. {
  247. this.turnDeck.Add(ce, );
  248. }
  249. }
  250. }
  251. foreach (KeyValuePair<string, int> c2 in tmpDeck)
  252. {
  253. if (c2.Value >= )
  254. {
  255. CardDB.cardIDEnum ce = CardDB.Instance.cardIdstringToEnum(c2.Key);
  256. if (ce != CardDB.cardIDEnum.None)
  257. {
  258. if (this.turnDeck.ContainsKey(ce))
  259. {
  260. Dictionary<CardDB.cardIDEnum, int> dictionary;
  261. CardDB.cardIDEnum key;
  262. (dictionary = this.turnDeck)[key = ce] = dictionary[key] + c2.Value;
  263. }
  264. else
  265. {
  266. this.turnDeck.Add(ce, c2.Value);
  267. }
  268. }
  269. }
  270. }
  271. Probabilitymaker.Instance.setOwnCardsOut(og);
  272. Probabilitymaker.Instance.setEnemyCardsOut(eg);
  273. bool isTurnStart = false;
  274. if (Ai.Instance.nextMoveGuess.mana == -)
  275. {
  276. isTurnStart = true;
  277. Ai.Instance.updateTwoTurnSim();
  278. }
  279. Probabilitymaker.Instance.setGraveYard(graveYard, isTurnStart);
  280. if (this.startDeck.Count != )
  281. {
  282. this.noDuplicates = true;
  283. foreach (int i in this.turnDeck.Values)
  284. {
  285. if (i > )
  286. {
  287. this.noDuplicates = false;
  288. break;
  289. }
  290. }
  291. }
  292. }

在updateEverything函数里面的this.getDecks();的下一行设置断点,发现这个执行完,就看到卡牌错误提示

  1. // HREngine.Bots.Silverfish
  2. // Token: 0x06000044 RID: 68 RVA: 0x00008154 File Offset: 0x00006354
  3. public bool updateEverything(Behavior botbase, int numcal, out bool sleepRetry)
  4. {
  5. this.needSleep = false;
  6. this.updateBehaveString(botbase);
  7. this.ownPlayerController = TritonHs.OurHero.ControllerId;
  8. Hrtprozis.Instance.clearAllRecalc();
  9. Handmanager.Instance.clearAllRecalc();
  10. this.getHerostuff();
  11. this.getMinions();
  12. this.getHandcards();
  13. this.getDecks();
  14. Hrtprozis.Instance.updateTurnDeck(this.turnDeck, this.noDuplicates);
  15. Hrtprozis.Instance.setOwnPlayer(this.ownPlayerController);
  16. Handmanager.Instance.setOwnPlayer(this.ownPlayerController);
  17. this.numOptionPlayedThisTurn = ;
  18. this.numOptionPlayedThisTurn += this.cardsPlayedThisTurn + this.ownHero.numAttacksThisTurn;
  19. foreach (Minion i in this.ownMinions)
  20. {
  21. if (i.Hp >= )
  22. {
  23. this.numOptionPlayedThisTurn += i.numAttacksThisTurn;
  24. }
  25. }
  26. List<HSCard> list = TritonHs.GetCards(CardZone.Graveyard, true);
  27. foreach (GraveYardItem gi in Probabilitymaker.Instance.turngraveyard)
  28. {
  29. if (gi.own)
  30. {
  31. foreach (HSCard entiti in list)
  32. {
  33. if (gi.entity == entiti.EntityId)
  34. {
  35. this.numOptionPlayedThisTurn += entiti.NumAttackThisTurn;
  36. break;
  37. }
  38. }
  39. }
  40. }
  41. Hrtprozis.Instance.updatePlayer(this.ownMaxMana, this.currentMana, this.cardsPlayedThisTurn, this.numMinionsPlayedThisTurn, this.numOptionPlayedThisTurn, this.ueberladung, this.lockedMana, TritonHs.OurHero.EntityId, TritonHs.EnemyHero.EntityId);
  42. Hrtprozis.Instance.updateSecretStuff(this.ownSecretList, this.enemySecretList.Count);
  43. Hrtprozis.Instance.updateHero(this.ownWeapon, this.heroname, this.heroAbility, this.ownAbilityisReady, this.ownHeroPowerCost, this.ownHero, );
  44. Hrtprozis.Instance.updateHero(this.enemyWeapon, this.enemyHeroname, this.enemyAbility, false, this.enemyHeroPowerCost, this.enemyHero, this.enemyMaxMana);
  45. Questmanager.Instance.updatePlayedMobs(this.gTurnStep);
  46. Hrtprozis.Instance.updateMinions(this.ownMinions, this.enemyMinions);
  47. Hrtprozis.Instance.updateLurkersDB(this.LurkersDB);
  48. Handmanager.Instance.setHandcards(this.handCards, this.anzcards, this.enemyAnzCards);
  49. Hrtprozis.Instance.updateFatigueStats(this.ownDecksize, this.ownHeroFatigue, this.enemyDecksize, this.enemyHeroFatigue);
  50. Hrtprozis.Instance.updateJadeGolemsInfo(GameState.Get().GetFriendlySidePlayer().GetTag(GAME_TAG.JADE_GOLEM), GameState.Get().GetOpposingSidePlayer().GetTag(GAME_TAG.JADE_GOLEM));
  51. Hrtprozis.Instance.updateTurnInfo(this.gTurn, this.gTurnStep);
  52. this.updateCThunInfobyCThun();
  53. Hrtprozis.Instance.updateCThunInfo(this.anzOgOwnCThunAngrBonus, this.anzOgOwnCThunHpBonus, this.anzOgOwnCThunTaunt);
  54. Hrtprozis.Instance.updateCrystalCore(this.ownCrystalCore);
  55. Hrtprozis.Instance.updateOwnMinionsInDeckCost0(this.ownMinionsCost0);
  56. Probabilitymaker.Instance.setEnemySecretGuesses(this.enemySecretList);
  57. sleepRetry = this.needSleep;
  58. bool result;
  59. if (sleepRetry && numcal == )
  60. {
  61. result = false;
  62. }
  63. else
  64. {
  65. if (!Hrtprozis.Instance.setGameRule)
  66. {
  67. RulesEngine.Instance.setCardIdRulesGame(this.ownHero.cardClass, this.enemyHero.cardClass);
  68. Hrtprozis.Instance.setGameRule = true;
  69. }
  70. Playfield p = new Playfield();
  71. p.enemyCardsOut = new Dictionary<CardDB.cardIDEnum, int>(Probabilitymaker.Instance.enemyCardsOut);
  72. if (this.lastpf != null)
  73. {
  74. if (this.lastpf.isEqualf(p))
  75. {
  76. return false;
  77. }
  78. if (p.gTurnStep > && Ai.Instance.nextMoveGuess.ownMinions.Count == p.ownMinions.Count)
  79. {
  80. if (Ai.Instance.nextMoveGuess.ownHero.Ready != p.ownHero.Ready && !p.ownHero.Ready)
  81. {
  82. sleepRetry = true;
  83. Helpfunctions.Instance.ErrorLog("[AI] Hero ready = " + p.ownHero.Ready + ". Attempting recover....");
  84. Ai.Instance.nextMoveGuess = new Playfield
  85. {
  86. mana = -
  87. };
  88. return false;
  89. }
  90. for (int j = ; j < p.ownMinions.Count; j++)
  91. {
  92. if (Ai.Instance.nextMoveGuess.ownMinions[j].Ready != p.ownMinions[j].Ready && !p.ownMinions[j].Ready)
  93. {
  94. sleepRetry = true;
  95. Helpfunctions.Instance.ErrorLog(string.Concat(new object[]
  96. {
  97. "[AI] Minion ready = ",
  98. p.ownMinions[j].Ready,
  99. " (",
  100. p.ownMinions[j].entitiyID,
  101. " ",
  102. p.ownMinions[j].handcard.card.cardIDenum,
  103. " ",
  104. p.ownMinions[j].name,
  105. "). Attempting recover...."
  106. }));
  107. Ai.Instance.nextMoveGuess = new Playfield
  108. {
  109. mana = -
  110. };
  111. return false;
  112. }
  113. }
  114. }
  115. Probabilitymaker.Instance.updateSecretList(p, this.lastpf);
  116. this.lastpf = p;
  117. }
  118. else
  119. {
  120. this.lastpf = p;
  121. }
  122. p = new Playfield();
  123. Helpfunctions.Instance.ErrorLog("calculating stuff... " + DateTime.Now.ToString("HH:mm:ss.ffff"));
  124. using (TritonHs.Memory.ReleaseFrame(true))
  125. {
  126. this.printstuff();
  127. Ai.Instance.dosomethingclever(botbase);
  128. }
  129. Helpfunctions.Instance.ErrorLog("calculating ended! " + DateTime.Now.ToString("HH:mm:ss.ffff"));
  130. if (this.sttngs.printRules > )
  131. {
  132. string[] rulesStr = Ai.Instance.bestplay.rulesUsed.Split(new char[]
  133. {
  134. '@'
  135. });
  136. if (rulesStr.Count<string>() > && rulesStr[] != "")
  137. {
  138. Helpfunctions.Instance.ErrorLog("ruleWeight " + Ai.Instance.bestplay.ruleWeight * -);
  139. foreach (string rs in rulesStr)
  140. {
  141. if (!(rs == ""))
  142. {
  143. Helpfunctions.Instance.ErrorLog("rule: " + rs);
  144. }
  145. }
  146. }
  147. }
  148. result = true;
  149. }
  150. return result;
  151. }

namespace HREngine.Bots

public class DefaultRoutine : IRoutine, IRunnable, IAuthored, IBase, IConfigurable

在update everything函数调用的地方设置断点,发现执行pdate everything函数,就有错误提示。

所以卡牌的错误,是在update everything里面出来的。

  1. // HREngine.Bots.DefaultRoutine
  2. // Token: 0x06000017 RID: 23 RVA: 0x00005A54 File Offset: 0x00003C54
  3. public async Task OurTurnLogic()
  4. {
  5. if (this.behave.BehaviorName() != DefaultRoutineSettings.Instance.DefaultBehavior)
  6. {
  7. this.behave = this.sf.getBehaviorByName(DefaultRoutineSettings.Instance.DefaultBehavior);
  8. Silverfish.Instance.lastpf = null;
  9. }
  10. if (this.learnmode && (TritonHs.IsInTargetMode() || TritonHs.IsInChoiceMode()))
  11. {
  12. await Coroutine.Sleep();
  13. }
  14. else if (TritonHs.IsInTargetMode())
  15. {
  16. if (this.dirtytarget >= )
  17. {
  18. DefaultRoutine.Log.Info("targeting...");
  19. HSCard source = null;
  20. if (this.dirtyTargetSource == )
  21. {
  22. source = TritonHs.OurHeroPowerCard;
  23. }
  24. else
  25. {
  26. source = this.getEntityWithNumber(this.dirtyTargetSource);
  27. }
  28. HSCard target = this.getEntityWithNumber(this.dirtytarget);
  29. if (target == null)
  30. {
  31. DefaultRoutine.Log.Error("target is null...");
  32. TritonHs.CancelTargetingMode();
  33. }
  34. else
  35. {
  36. this.dirtytarget = -;
  37. this.dirtyTargetSource = -;
  38. if (source == null)
  39. {
  40. await TritonHs.DoTarget(target);
  41. }
  42. else
  43. {
  44. await source.DoTarget(target);
  45. }
  46. await Coroutine.Sleep();
  47. }
  48. }
  49. else
  50. {
  51. DefaultRoutine.Log.Error("target failure...");
  52. TritonHs.CancelTargetingMode();
  53. }
  54. }
  55. else if (TritonHs.IsInChoiceMode())
  56. {
  57. await Coroutine.Sleep( + this.makeChoice());
  58. switch (this.dirtychoice)
  59. {
  60. case :
  61. TritonHs.ChooseOneClickMiddle();
  62. break;
  63. case :
  64. TritonHs.ChooseOneClickLeft();
  65. break;
  66. case :
  67. TritonHs.ChooseOneClickRight();
  68. break;
  69. }
  70. this.dirtychoice = -;
  71. await Coroutine.Sleep();
  72. }
  73. else
  74. {
  75. bool sleepRetry = false;
  76. bool templearn = Silverfish.Instance.updateEverything(this.behave, , out sleepRetry);
  77. if (sleepRetry)
  78. {
  79. DefaultRoutine.Log.Error("[AI] Readiness error. Attempting recover...");
  80. await Coroutine.Sleep();
  81. templearn = Silverfish.Instance.updateEverything(this.behave, , out sleepRetry);
  82. }
  83. if (templearn)
  84. {
  85. this.printlearnmode = true;
  86. }
  87. if (this.learnmode)
  88. {
  89. if (this.printlearnmode)
  90. {
  91. Ai.Instance.simmulateWholeTurnandPrint();
  92. }
  93. this.printlearnmode = false;
  94. await Coroutine.Sleep();
  95. }
  96. else
  97. {
  98. Action moveTodo = Ai.Instance.bestmove;
  99. if (moveTodo == null || moveTodo.actionType == actionEnum.endturn || Ai.Instance.bestmoveValue < -9999f)
  100. {
  101. bool doEndTurn = false;
  102. bool doConcede = false;
  103. if (Ai.Instance.bestmoveValue > -10000f)
  104. {
  105. doEndTurn = true;
  106. }
  107. else if (Settings.Instance.concedeMode != )
  108. {
  109. doConcede = true;
  110. }
  111. else if (new Playfield().ownHeroHasDirectLethal())
  112. {
  113. Playfield lastChancePl = Ai.Instance.bestplay;
  114. bool lastChance = false;
  115. if (lastChancePl.owncarddraw > )
  116. {
  117. foreach (Handmanager.Handcard hc in lastChancePl.owncards)
  118. {
  119. if (hc.card.name == CardDB.cardName.unknown)
  120. {
  121. lastChance = true;
  122. }
  123. }
  124. if (!lastChance)
  125. {
  126. doConcede = true;
  127. }
  128. }
  129. else
  130. {
  131. doConcede = true;
  132. }
  133. if (doConcede)
  134. {
  135. foreach (Minion i in lastChancePl.ownMinions)
  136. {
  137. if (i.playedThisTurn)
  138. {
  139. CardDB.cardName name = i.handcard.card.name;
  140. if (name <= CardDB.cardName.nzoththecorruptor)
  141. {
  142. if (name != CardDB.cardName.barongeddon)
  143. {
  144. if (name != CardDB.cardName.cthun)
  145. {
  146. if (name == CardDB.cardName.nzoththecorruptor)
  147. {
  148. lastChance = true;
  149. }
  150. }
  151. else
  152. {
  153. lastChance = true;
  154. }
  155. }
  156. else if (lastChancePl.enemyHero.Hp < )
  157. {
  158. lastChance = true;
  159. }
  160. }
  161. else if (name != CardDB.cardName.ragnarosthefirelord)
  162. {
  163. if (name != CardDB.cardName.sirfinleymrrgglton)
  164. {
  165. if (name == CardDB.cardName.yoggsaronhopesend)
  166. {
  167. lastChance = true;
  168. }
  169. }
  170. else
  171. {
  172. lastChance = true;
  173. }
  174. }
  175. else if (lastChancePl.enemyHero.Hp < )
  176. {
  177. lastChance = true;
  178. }
  179. }
  180. }
  181. }
  182. if (lastChance)
  183. {
  184. doConcede = false;
  185. }
  186. }
  187. else if (moveTodo == null || moveTodo.actionType == actionEnum.endturn)
  188. {
  189. doEndTurn = true;
  190. }
  191. if (doEndTurn)
  192. {
  193. Helpfunctions.Instance.ErrorLog("end turn");
  194. await TritonHs.EndTurn();
  195. return;
  196. }
  197. if (doConcede)
  198. {
  199. Helpfunctions.Instance.ErrorLog("Lethal detected. Concede...");
  200. Helpfunctions.Instance.logg("Concede... Lethal detected###############################################");
  201. TritonHs.Concede(true);
  202. return;
  203. }
  204. }
  205. Helpfunctions.Instance.ErrorLog("play action");
  206. if (moveTodo == null)
  207. {
  208. Helpfunctions.Instance.ErrorLog("moveTodo == null. EndTurn");
  209. await TritonHs.EndTurn();
  210. }
  211. else
  212. {
  213. moveTodo.print(false);
  214. if (moveTodo.actionType == actionEnum.playcard)
  215. {
  216. Questmanager.Instance.updatePlayedCardFromHand(moveTodo.card);
  217. HSCard cardtoplay = this.getCardWithNumber(moveTodo.card.entity);
  218. if (cardtoplay == null)
  219. {
  220. Helpfunctions.Instance.ErrorLog("[Tick] cardtoplay == null");
  221. }
  222. else if (moveTodo.target != null)
  223. {
  224. HSCard target2 = this.getEntityWithNumber(moveTodo.target.entitiyID);
  225. if (target2 != null)
  226. {
  227. Helpfunctions.Instance.ErrorLog(string.Concat(new object[]
  228. {
  229. "play: ",
  230. cardtoplay.Name,
  231. " (",
  232. cardtoplay.EntityId,
  233. ") target: ",
  234. target2.Name,
  235. " (",
  236. target2.EntityId,
  237. ")"
  238. }));
  239. Helpfunctions.Instance.logg(string.Concat(new object[]
  240. {
  241. "play: ",
  242. cardtoplay.Name,
  243. " (",
  244. cardtoplay.EntityId,
  245. ") target: ",
  246. target2.Name,
  247. " (",
  248. target2.EntityId,
  249. ") choice: ",
  250. moveTodo.druidchoice
  251. }));
  252. if (moveTodo.druidchoice >= )
  253. {
  254. this.dirtytarget = moveTodo.target.entitiyID;
  255. this.dirtychoice = moveTodo.druidchoice;
  256. this.choiceCardId = moveTodo.card.card.cardIDenum.ToString();
  257. }
  258. this.dirtyTargetSource = moveTodo.card.entity;
  259. this.dirtytarget = moveTodo.target.entitiyID;
  260. await cardtoplay.Pickup();
  261. if (moveTodo.card.card.type == CardDB.cardtype.MOB)
  262. {
  263. await cardtoplay.UseAt(moveTodo.place);
  264. }
  265. else if (moveTodo.card.card.type == CardDB.cardtype.WEAPON)
  266. {
  267. await cardtoplay.UseOn(target2.Card);
  268. }
  269. else if (moveTodo.card.card.type == CardDB.cardtype.SPELL)
  270. {
  271. await cardtoplay.UseOn(target2.Card);
  272. }
  273. else
  274. {
  275. await cardtoplay.UseOn(target2.Card);
  276. }
  277. }
  278. else
  279. {
  280. Helpfunctions.Instance.ErrorLog("[AI] Target is missing. Attempting recover...");
  281. Helpfunctions.Instance.logg("[AI] Target " + moveTodo.target.entitiyID + "is missing. Attempting recover...");
  282. }
  283. await Coroutine.Sleep();
  284. }
  285. else
  286. {
  287. Helpfunctions.Instance.ErrorLog(string.Concat(new object[]
  288. {
  289. "play: ",
  290. cardtoplay.Name,
  291. " (",
  292. cardtoplay.EntityId,
  293. ") target nothing"
  294. }));
  295. Helpfunctions.Instance.logg(string.Concat(new object[]
  296. {
  297. "play: ",
  298. cardtoplay.Name,
  299. " (",
  300. cardtoplay.EntityId,
  301. ") choice: ",
  302. moveTodo.druidchoice
  303. }));
  304. if (moveTodo.druidchoice >= )
  305. {
  306. this.dirtychoice = moveTodo.druidchoice;
  307. this.choiceCardId = moveTodo.card.card.cardIDenum.ToString();
  308. }
  309. this.dirtyTargetSource = -;
  310. this.dirtytarget = -;
  311. await cardtoplay.Pickup();
  312. if (moveTodo.card.card.type == CardDB.cardtype.MOB)
  313. {
  314. await cardtoplay.UseAt(moveTodo.place);
  315. }
  316. else
  317. {
  318. await cardtoplay.Use();
  319. }
  320. await Coroutine.Sleep();
  321. }
  322. }
  323. else if (moveTodo.actionType == actionEnum.attackWithMinion)
  324. {
  325. HSCard attacker = this.getEntityWithNumber(moveTodo.own.entitiyID);
  326. HSCard target3 = this.getEntityWithNumber(moveTodo.target.entitiyID);
  327. if (attacker != null)
  328. {
  329. if (target3 != null)
  330. {
  331. Helpfunctions.Instance.ErrorLog("minion attack: " + attacker.Name + " target: " + target3.Name);
  332. Helpfunctions.Instance.logg("minion attack: " + attacker.Name + " target: " + target3.Name);
  333. await attacker.DoAttack(target3);
  334. }
  335. else
  336. {
  337. Helpfunctions.Instance.ErrorLog("[AI] Target is missing. Attempting recover...");
  338. Helpfunctions.Instance.logg("[AI] Target " + moveTodo.target.entitiyID + "is missing. Attempting recover...");
  339. }
  340. }
  341. else
  342. {
  343. Helpfunctions.Instance.ErrorLog("[AI] Attacker is missing. Attempting recover...");
  344. Helpfunctions.Instance.logg("[AI] Attacker " + moveTodo.own.entitiyID + " is missing. Attempting recover...");
  345. }
  346. await Coroutine.Sleep();
  347. }
  348. else if (moveTodo.actionType == actionEnum.attackWithHero)
  349. {
  350. HSCard attacker2 = this.getEntityWithNumber(moveTodo.own.entitiyID);
  351. HSCard target4 = this.getEntityWithNumber(moveTodo.target.entitiyID);
  352. if (attacker2 != null)
  353. {
  354. if (target4 != null)
  355. {
  356. this.dirtytarget = moveTodo.target.entitiyID;
  357. Helpfunctions.Instance.ErrorLog("heroattack: " + attacker2.Name + " target: " + target4.Name);
  358. Helpfunctions.Instance.logg("heroattack: " + attacker2.Name + " target: " + target4.Name);
  359. this.dirtyTargetSource = moveTodo.own.entitiyID;
  360. this.dirtytarget = moveTodo.target.entitiyID;
  361. await attacker2.DoAttack(target4);
  362. }
  363. else
  364. {
  365. Helpfunctions.Instance.ErrorLog("[AI] Target is missing. Attempting recover...");
  366. Helpfunctions.Instance.logg("[AI] Target " + moveTodo.target.entitiyID + "is missing (H). Attempting recover...");
  367. }
  368. }
  369. else
  370. {
  371. Helpfunctions.Instance.ErrorLog("[AI] Attacker is missing. Attempting recover...");
  372. Helpfunctions.Instance.logg("[AI] Attacker " + moveTodo.own.entitiyID + " is missing (H). Attempting recover...");
  373. }
  374. await Coroutine.Sleep();
  375. }
  376. else if (moveTodo.actionType == actionEnum.useHeroPower)
  377. {
  378. HSCard cardtoplay2 = TritonHs.OurHeroPowerCard;
  379. if (moveTodo.target != null)
  380. {
  381. HSCard target5 = this.getEntityWithNumber(moveTodo.target.entitiyID);
  382. if (target5 != null)
  383. {
  384. Helpfunctions.Instance.ErrorLog("use ablitiy: " + cardtoplay2.Name + " target " + target5.Name);
  385. Helpfunctions.Instance.logg(string.Concat(new string[]
  386. {
  387. "use ablitiy: ",
  388. cardtoplay2.Name,
  389. " target ",
  390. target5.Name,
  391. (moveTodo.druidchoice > ) ? (" choice: " + moveTodo.druidchoice) : ""
  392. }));
  393. if (moveTodo.druidchoice > )
  394. {
  395. this.dirtytarget = moveTodo.target.entitiyID;
  396. this.dirtychoice = moveTodo.druidchoice;
  397. this.choiceCardId = moveTodo.card.card.cardIDenum.ToString();
  398. }
  399. this.dirtyTargetSource = ;
  400. this.dirtytarget = moveTodo.target.entitiyID;
  401. await cardtoplay2.Pickup();
  402. await cardtoplay2.UseOn(target5.Card);
  403. }
  404. else
  405. {
  406. Helpfunctions.Instance.ErrorLog("[AI] Target is missing. Attempting recover...");
  407. Helpfunctions.Instance.logg("[AI] Target " + moveTodo.target.entitiyID + "is missing. Attempting recover...");
  408. }
  409. await Coroutine.Sleep();
  410. }
  411. else
  412. {
  413. Helpfunctions.Instance.ErrorLog("use ablitiy: " + cardtoplay2.Name + " target nothing");
  414. Helpfunctions.Instance.logg("use ablitiy: " + cardtoplay2.Name + " target nothing" + ((moveTodo.druidchoice > ) ? (" choice: " + moveTodo.druidchoice) : ""));
  415. if (moveTodo.druidchoice >= )
  416. {
  417. this.dirtychoice = moveTodo.druidchoice;
  418. this.choiceCardId = moveTodo.card.card.cardIDenum.ToString();
  419. }
  420. this.dirtyTargetSource = -;
  421. this.dirtytarget = -;
  422. await cardtoplay2.Pickup();
  423. }
  424. }
  425. else
  426. {
  427. await TritonHs.EndTurn();
  428. }
  429. }
  430. }
  431. }
  432. }

最后发现错误提示,是从

namespace HREngine.Bots

public class CardDB里面报错的

把cardid的字符串转换为cardIDEnum的时候出错

  1. public CardDB.cardIDEnum cardIdstringToEnum(string s)
  2. {
  3. CardDB.cardIDEnum CardEnum;
  4. CardDB.cardIDEnum result;
  5. if (Enum.TryParse<CardDB.cardIDEnum>(s, false, out CardEnum))
  6. {
  7. result = CardEnum;
  8. }
  9. else
  10. {
  11. Logger.GetLoggerInstanceForType().ErrorFormat("[Unidentified card ID :" + s + "]", new object[]);
  12. result = CardDB.cardIDEnum.None;
  13. }
  14. return result;
  15. }

根据我的印象,https://github.com/HearthSim/Hearthdb 这个项目就是用来生成卡牌的。

1.生成data

clone项目,编译之后,得到能识别的的CardDefs.xml。然后重命名成_carddb.txt,然后替换掉HearthBuddy里面的

2.自己实现卡牌

另外,这个文件不在HearthBuddy的exe里面,是外部加载进来的。HearthbuddyRelease\Routines\DefaultRoutine\Silverfish\ai\CardDB.cs

卡牌的实现需要自己写在Silverfish\cards文件夹下,并且卡牌在实现的时候,根据需要从Silverfish\ai的某一个类中继承,实现对应的方法

github上面尝试找了一下实现https://github.com/search?l=C%23&o=desc&q=getBattlecryEffect&s=indexed&type=Code

<Entity CardID="DAL_010" ID="51375" version="2">
<MasterPower>773590e3-24fa-4564-994a-94049b32d3f3</MasterPower>
<Tag enumID="185" name="CARDNAME" type="LocString">
<deDE>Togwaggels Plan</deDE>
<enUS>Togwaggle's Scheme</enUS>
<esES>Plan de Togafloja</esES>
<esMX>Complot de Togwaggle</esMX>
<frFR>Manœuvre de Cire-Pilleur</frFR>
<itIT>Piano di Cobaldo</itIT>
<jaJP>トグワグルの計略</jaJP>
<koKR>토그왜글의 계략</koKR>
<plPL>Intryga Trzęsibrzucha</plPL>
<ptBR>Estratagema de Fubalumba</ptBR>
<ruRU>Козни Вихлепыха</ruRU>
<thTH>แผนการของท็อกแว็กเกิล</thTH>
<zhCN>托瓦格尔的阴谋</zhCN>
<zhTW>托戈瓦哥的陰謀</zhTW>
</Tag>

<Entity CardID="DAL_415" ID="52111" version="2">
<MasterPower>2ef4d4c2-dbdf-4ae4-9f14-079984458f86</MasterPower>
<Tag enumID="185" name="CARDNAME" type="LocString">
<deDE>Ü.B.E.L.-Täter</deDE>
<enUS>EVIL Miscreant</enUS>
<esES>Malhechor del MAL</esES>
<esMX>Bellaco del MAL</esMX>
<frFR>Voyou du M.A.L.</frFR>
<itIT>Furfante del M.A.L.E.</itIT>
<jaJP>悪党同盟の悪漢</jaJP>
<koKR>잔.악.무.도. 악당</koKR>
<plPL>Szubrawiec Ligi Z.Ł.A.</plPL>
<ptBR>Mandrião da MAL</ptBR>
<ruRU>Негодяй ЗЛА</ruRU>
<thTH>จอมโฉด EVIL</thTH>
<zhCN>怪盗恶霸</zhCN>
<zhTW>邪惡陣線無賴</zhTW>
</Tag>

对了,貌似贴吧已经有部分教程了。https://tieba.baidu.com/p/5663869359

偶数萨电鳗狼王添加方法

==================================
1.编写新卡SIM,
在\Hearthbuddy\Routines\DefaultRoutine\Silverfish\cards\,
在目录下新建一个Sim_扩展包缩写+卡牌编号.cs文件,
编写SIM后保存。
==================================
2.编写并增加新卡识别信息,
\Hearthbuddy\Routines\DefaultRoutine\Silverfish\data\ 下的 _carddb.txt 文件,
其中存储所有卡牌信息。
含:185、184等等。
注意特效卡牌后面添加playRequirement,
每个节点后退两个字符。
(上述是新卡描述)
==================================
3.增加新卡编号及英文名称
在\Routines\DefaultRoutine\Silverfish\ai的CardDB.cs中的3550行后增加新卡
扩展包简称_卡牌编号,
如:
LOOT_149,
LOOT_149e,
扩展包简称均为大写,可以联想GVG,
==================================
在\Routines\DefaultRoutine\Silverfish\ai的CardDB.cs中的6303行后,增加新增卡牌英文名称。
注意卡牌英文名称没有空格且奇数偶数卡牌需添加两个名字,编写两个卡牌信息。
2费电鳗murksparkeel
6费偶数狼王geengreymane
战斗号角calltoarms
5费吵吵gigglingInventor
5费菌菇fungalmancer
3费荆棘Hench-ClanThug
刺杀花vilespineslayer
9费奇数bakuthemooneater

实际操作

发现阴燃电鳗无法识别

https://github.com/chucklu/HearthBuddyAnalyze/tree/master/CardQuery

使用工具,查询

阴燃电鳗的战吼效果和火元素类似,查找火元素的编号CS2_042,

然后在solution explorer搜索这个编号,找到

注释居然是法语

  1. class Sim_CS2_042 : SimTemplate //fireelemental
  2. {
  3.  
  4. // kampfschrei:/ verursacht 3 schaden.
  5. public override void getBattlecryEffect(Playfield p, Minion own, Minion target, int choice)
  6. {
  7. int dmg = ;
  8. p.minionGetDamageOrHeal(target, dmg);
  9.  
  10. }
  11.  
  12. }

public enum cardIDEnum 里面需要新加一个卡牌枚举

可能还需要加一个类似Pen_CS2_042.cs的

在整个解决方案搜火元素的名字fireelemental

public enum cardName需要添加一个枚举,这里的cardName就是在下面记录伤害和记录血量的地方使用

public Dictionary<CardDB.cardName, int> DamageTargetDatabase = new Dictionary<CardDB.cardName, int>();  记录伤害的

Dictionary<CardDB.cardName, int> GangUpDatabase = new Dictionary<CardDB.cardName, int>(); 这个应该是卡牌的评分

GangUpDatabase.Add(CardDB.cardName.emperorthaurissan, 5);

{
"Id": "BRM_028",
"DbfId": 2262,
"Name": "索瑞森大帝",
"Text": "在你的回合结束时,你所有手牌的法力值消耗减少(1)点。",
"FlavorText": "把一个邪恶的炎魔之王召唤到这个世界上,然后看着这个家伙奴役了他所有的子民并非是他最为后悔的事情。",
"Class": "NEUTRAL",
"Rarity": "LEGENDARY",
"Type": "MINION",
"Race": "INVALID",
"Set": "BRM",
"Faction": "INVALID",
"Cost": 6,
"Attack": 5,
"Health": 5,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Wayne Reynolds",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.etherealpeddler, 3);

{
"Id": "KAR_070",
"DbfId": 39700,
"Name": "虚灵商人",
"Text": "<b>战吼:</b>如果你的手牌中有其他职业的卡牌,则其法力值消耗减少(2)点。",
"FlavorText": "虚灵以热衷收集和买卖各种魔法物品和神器而著称,比那些贪婪的地精靠谱多了。",
"Class": "ROGUE",
"Rarity": "RARE",
"Type": "MINION",
"Race": "INVALID",
"Set": "KARA",
"Faction": "INVALID",
"Cost": 5,
"Attack": 5,
"Health": 6,
"Durability": 0,
"Armor": 0,
"Mechanics": [
"Battlecry"
],
"ArtistName": "Alex Horley Orlandelli",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.felcannon, 0);

{
"Id": "GVG_020",
"DbfId": 1997,
"Name": "邪能火炮",
"Text": "在你的回合结束时,对一个非机械随从造成2点伤害。",
"FlavorText": "包装盒上写着:全新改良,比旧款更邪门!",
"Class": "WARLOCK",
"Rarity": "RARE",
"Type": "MINION",
"Race": "MECHANICAL",
"Set": "GVG",
"Faction": "INVALID",
"Cost": 4,
"Attack": 3,
"Health": 5,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Matt Gaser",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.fireelemental, 5);

{
"Id": "CS2_042",
"DbfId": 189,
"Name": "火元素",
"Text": "<b>战吼:</b>造成3点伤害。",
"FlavorText": "他从来不洗澡。嗯...",
"Class": "SHAMAN",
"Rarity": "FREE",
"Type": "MINION",
"Race": "ELEMENTAL",
"Set": "CORE",
"Faction": "NEUTRAL",
"Cost": 6,
"Attack": 6,
"Health": 5,
"Durability": 0,
"Armor": 0,
"Mechanics": [
"Battlecry"
],
"ArtistName": "Ralph Horsley",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": false
}

GangUpDatabase.Add(CardDB.cardName.fireguarddestroyer, 4);

{
"Id": "BRM_012",
"DbfId": 2290,
"Name": "火焰驱逐者",
"Text": "<b>战吼:</b>获得1-4点攻击力。<b>过载:</b>(1)",
"FlavorText": "很多火元素竞相面试“火焰驱逐者”的职位,但拉格纳罗斯认为只有极少数火元素能够胜任。",
"Class": "SHAMAN",
"Rarity": "COMMON",
"Type": "MINION",
"Race": "ELEMENTAL",
"Set": "BRM",
"Faction": "INVALID",
"Cost": 4,
"Attack": 3,
"Health": 6,
"Durability": 0,
"Armor": 0,
"Mechanics": [
"Battlecry"
],
"ArtistName": "Paul Mafayon",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.flametonguetotem, 4);

{
"Id": "EX1_565",
"DbfId": 1008,
"Name": "火舌图腾",
"Text": "相邻的随从获得+2攻击力。",
"FlavorText": "图腾制造师喜欢用最稀有的木材来打造图腾。甚至有传言说,这些图腾是由埃隆巴克保护者身上的树皮做的。",
"Class": "SHAMAN",
"Rarity": "FREE",
"Type": "MINION",
"Race": "TOTEM",
"Set": "CORE",
"Faction": "NEUTRAL",
"Cost": 3,
"Attack": 0,
"Health": 3,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Jonathan Ryder",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": false
}

GangUpDatabase.Add(CardDB.cardName.flamewaker, 4);

{
"Id": "BRM_002",
"DbfId": 2275,
"Name": "火妖",
"Text": "在你施放一个法术后,造成2点伤害,随机分配到所有敌人身上。",
"FlavorText": "他们深居于炎热的洞窟之中,听候管理者的命令:消灭一切胆敢打扰炎魔之王的敌人。",
"Class": "MAGE",
"Rarity": "RARE",
"Type": "MINION",
"Race": "INVALID",
"Set": "BRM",
"Faction": "INVALID",
"Cost": 3,
"Attack": 2,
"Health": 4,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Alex Horley Orlandelli",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.flesheatingghoul, 0);

{
"Id": "tt_004",
"DbfId": 397,
"Name": "腐肉食尸鬼",
"Text": "每当一个随从死亡,便获得+1攻击力。",
"FlavorText": "诟病食尸鬼吃“腐肉”其实对它们并不公平,它们只是没有别的可吃了而已。",
"Class": "NEUTRAL",
"Rarity": "COMMON",
"Type": "MINION",
"Race": "INVALID",
"Set": "EXPERT1",
"Faction": "NEUTRAL",
"Cost": 3,
"Attack": 2,
"Health": 3,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Alex Horley Orlandelli",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": false
}

GangUpDatabase.Add(CardDB.cardName.floatingwatcher, 0);  漂浮观察者,术士卡,544

{
"Id": "GVG_100",
"DbfId": 2068,
"Name": "漂浮观察者",
"Text": "每当你的英雄在你的回合受到伤害,便获得+2/+2。",
"FlavorText": "和他对话时,你很难与之进行眼神交流。",
"Class": "WARLOCK",
"Rarity": "COMMON",
"Type": "MINION",
"Race": "DEMON",
"Set": "GVG",
"Faction": "INVALID",
"Cost": 5,
"Attack": 4,
"Health": 4,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "Todd Lockwood",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

GangUpDatabase.Add(CardDB.cardName.foereaper4000, 1);   死神4000型,中立卡

{
"Id": "GVG_113",
"DbfId": 2081,
"Name": "死神4000型",
"Text": "同时对其攻击目标相邻的随从造成伤害。",
"FlavorText": "对于田里的庄稼来说,所有的收割机都是死神。",
"Class": "NEUTRAL",
"Rarity": "LEGENDARY",
"Type": "MINION",
"Race": "MECHANICAL",
"Set": "GVG",
"Faction": "INVALID",
"Cost": 8,
"Attack": 6,
"Health": 9,
"Durability": 0,
"Armor": 0,
"Mechanics": [],
"ArtistName": "James Ryman",
"EntourageCardIds": [],
"DefaultLanguage": "zhCN",
"Collectible": true,
"IsWild": true
}

HearthBuddy卡牌无法识别的更多相关文章

  1. HearthBuddy卡组

    偶数萨 手打两天已上传说,各位加油  欧洲牧羊人 ### 火元素换艾雅# 职业:萨满祭司# 模式:狂野模式## 2x (2) 图腾魔像        # 2x (2) 大漩涡传送门   # 2x (2 ...

  2. 使用UIKit制作卡牌游戏(三)ios游戏篇

    译者: Lao Jiang | 原文作者: Matthijs Hollemans写于2012/07/13 转自朋友Tommy 的翻译,自己只翻译了这第三篇教程. 原文地址: http://www.ra ...

  3. BZOJ 4205: 卡牌配对

    4205: 卡牌配对 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 173  Solved: 76[Submit][Status][Discuss] ...

  4. CCOrbitCamera卡牌翻转效果

    static CCOrbitCamera* create(float t, float radius, float deltaRadius, float angleZ, float deltaAngl ...

  5. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  6. JLOI 2013 卡牌游戏

    问题描述: N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄家首先 ...

  7. cocos2d-x 卡牌翻牌效果的实现

    转自:http://blog.csdn.net/yanghuiliu/article/details/9115833 这个能实现翻牌的action就是CCOrbitCamera. static CCO ...

  8. [JLOI2013]卡牌游戏

    [题目描述 Description] N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡 ...

  9. [bzoj3191] [JLOI2013]卡牌游戏

    概率DP. 首先由题解可得>_<,胜出概率只与剩余人数.与庄家的相对位置有关. 所以设f[i][j]表示剩下i个人,从庄家开始第j个人的胜利概率... 根据卡牌一通乱搞即可... #inc ...

随机推荐

  1. 文档.Write()和文档.Writeln()石材

    文档.Write()和文档.Writeln()文档是Javascript对象,其中封装了许多有用的方法,其中Write()和Writeln()是直接从浏览器窗口输出文本信息的方法.文件.Write() ...

  2. winfrom---Window 消息大全

    最近正在捣腾winfrom,遇到了关于window消息这一块的东西,正好在网上看到“微wx笑”的总结. 原文地址:http://blog.csdn.net/testcs_dn/article/deta ...

  3. Go语言并发机制

    Go语言中的并发 使用goroutine编程 使用 go 关键字用来创建 goroutine .将go声明放到一个需调用的函数之前,在相同地址空间调用运行这个函数,这样该函数执行时便会作为一个独立的并 ...

  4. mac下JDK的安装路径

    苹果系统已经包含完整的J2SE,其中就有JDK和JVM(苹果叫VM).当然如果要升级JDK,那当然要自己下载安装了. 在MAC系统中,jdk的安装路径与windows不同,默认目录是:/System/ ...

  5. Nginx 无法重启

    报错如下 Starting nginx... nginx (pid)already running. 重启nginx时,说多个进程已存在,,, 执行 ps -ef | grep nginx 发现 有多 ...

  6. 微信获取用户列表的json字符串解析

    今天学习微信遇到一个json的解析,但是因为自己的模型思维和思考能力很差一直困扰最后经过询问解决的问题,其实问题很简单总结起来就是json的解析: 注释:今天主要是讲怎样解析json的所以其他方法就只 ...

  7. P4149 距离为K的点对(最少边数) n=200000 点分治

    这题数据范围变成了200000 n^2就过不了 同时要求求的是最少的边数 不能容斥 #include<bits/stdc++.h> using namespace std; ; ; ], ...

  8. springboot-拦截器redis注入空问题解决

    转自:https://blog.csdn.net/liuyang1835189/article/details/81056162 主要问题是在拦截器的配置类里面,配置的类,spring容器无法获取,所 ...

  9. Git-------常用操作记录

    说明: 一般情况下,git要将内容提交到本地仓库,都是先将内容提交到暂存区,然后再从暂存区提交到本地仓库. 常用命令(一个简单的示例操作): git init:会默认创建一个分支,命名为master ...

  10. Hibernate的CRUD配置及简单使用

    参考博客:https://blog.csdn.net/qq_38977097/article/details/81326503 1.首先是jar包,可以在官网下载. 或者点击下面链接下载 链接:htt ...