/** Register the user onto a server. * * 用户注册/登录 (由于钱包功能尚不支持,Demo阶段暂时使用用户邮箱/密码作为认证方法。若有变动将在Global.VerifyUser()方法里变更实现) * 返回:该用户所有卡牌具体信息。若在该服务器上新账户,为用户新建若干卡牌。 * * Check psw/signature first, then * If the user does exist already, * If user exist on current server, consider as login in. * If user does exist on another server, transfer user to this server. * Else, create cards for this user. Need attach some GAS... * * Return: S<header> * */ private static byte[] Register(Credential credential, BigInteger serverId, string nickName, BigInteger iconID) { byte[] userData = RW.FindDataUser(credential.email); if (userData.Length != 0) { //Exists return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.Duplicated)); } else { byte[] psdHash = Hash256(Op.String2Bytes(credential.psw)); User user = new User(); user.address = credential.address; user.email = credential.email; user.pswHash = psdHash; user.nickName = nickName; user.icon = iconID; user.serverID = serverId; user.warID = Op.Void(); user.city = Const.numCities; //user.cardIDs = new byte[0]; RW.SaveUser(user); return(NuTP.RespDataSucWithBody(RW.User2Bytes(user))); } }
//创世初始化 public static byte[] Genesis() { if (Runtime.CheckWitness(Owner)) { //年份实际从1开始。第一区块无丕料 byte[] startYear = new byte[1] { 1 }; NuIO.SetStorageWithKey(keyYear, startYear); //Storage.Put(Storage.CurrentContext, keyYear, 0); //年份为0 BigInteger water = 100; BigInteger soil = 100; BigInteger wind = 100; BigInteger fire = 100; AllocatePimetal(Pimetal.Water, water); AllocatePimetal(Pimetal.Soil, soil); AllocatePimetal(Pimetal.Wind, wind); AllocatePimetal(Pimetal.Fire, fire); return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Unauthorized)); } }
public static object Main(string operation, params object[] args) { if (Runtime.Trigger == TriggerType.Verification) { if (operation == "post") { byte[] quizBytes = (byte[])args[0]; return(Post(quizBytes)); } } if (operation == "getQuiz") { BigInteger quizID = (BigInteger)args[0]; return(GetQuiz(quizID)); } if (operation == "getMessage") { BigInteger quizID = (BigInteger)args[0]; return(GetQuizMessage(quizID)); } return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.NotFound)); //return 404 }
// <emails> = [S<email>*] //<FakeUsers> = [S<user>*] private static byte[] FakeUsers(BigInteger serverId, byte[] emails) { byte[] body = Op.Void(); if (Runtime.CheckWitness(Owner)) { int numEmails = emails.SizeTable(); for (int i = 0; i < numEmails; i++) { string email = NuSD.SplitTblStr(emails, i); User user = new User { address = Op.Void(), email = email, pswHash = Op.Void(), nickName = "Fake", icon = 0, serverID = serverId, warID = Op.Void(), city = Const.numCities }; user.cards = GenerateRandomCards(user, 10); RW.SaveUser(user); body.AddSeg(RW.User2Bytes(user)); } return(NuTP.RespDataSucWithBody(body)); } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
/**Generate a random card*/ public static byte[] RandomCard(byte[] ownerId, byte[] cardId, string name) { Card cardOrig = ReadCard(cardId); if (cardOrig == null) { byte[] newLvData = Hash256(Op.JoinTwoByteArray(ownerId, Op.BigInt2Bytes(Blockchain.GetHeight()))); Card card = new Card { id = cardId, name = name, birthBlock = Blockchain.GetHeight(), level = Op.Bytes2BigInt(newLvData) % 3, ownerId = ownerId, isLive = true }; SaveCard(card); return(NuTP.RespDataSucWithBody(Card2Bytes(card))); } else { return(NuTP.RespDataWithCode(Error.Dom, Error.AlreadyExist)); } }
/** * In the 1st stage of each game, players are only allowed to submit the * hidden number's hash, rather than it hidden value itself. */ public static byte[] PutEntry(BigInteger gameId, byte[] address, byte[] pick, byte[] hiddenHash) { Game game = GetGame(gameId); if (game == null) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } else { if (Blockchain.GetHeight() >= game.heightStage1) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Forbidden));; } else { Entry entry = new Entry(); entry.gameId = gameId; entry.address = address; entry.pick = pick; entry.hiddenHash = hiddenHash; byte[] data = entry.Serialize(); BigInteger id = NumEntries(gameId); NuIO.SetStorageWithKeyPath(data, Global.keyGame, Op.BigInt2String(gameId), Global.keyEntry, Op.BigInt2String(id)); game.numEntries += 1; NuIO.SetStorageWithKeyPath(game.Serialize(), Global.keyGame, Op.BigInt2String(gameId)); return(NuTP.RespDataSucWithBody(data)); } } }
//Main Entrance public static Object Main(string operation, params object[] args) { if (operation == "randomCard") { byte[] ownerId = (byte[])args[0]; byte[] cardId = (byte[])args[1]; string cardName = (string)args[2]; return(RandomCard(ownerId, cardId, cardName)); } if (operation == "getCard") { //Used Internally Only byte[] cardId = (byte[])args[0]; Card card = ReadCard(cardId); byte[] cardData = Card2Bytes(card); return(NuTP.RespDataSucWithBody(cardData)); } if (operation == "cardMerge") { byte[] cardID1 = (byte[])args[0]; byte[] cardID2 = (byte[])args[1]; string name = (string)args[2]; return(CardMerge(cardID1, cardID2, name)); } //... Other operations return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.NotFound)); }
/** All the completed wars related with particular user with "maximum" recent items. * * 获取某用户已完成战役列表(最近的maximum个)。返回:一组War的列表 * * * Return: Array of War Object */ private static byte[] GetUserSeiges(Credential credential, string email, BigInteger maximum) { User user = RW.FindUser(email); BigInteger tot = RW.NumUserSiegeHistory(user); BigInteger num = (tot > maximum) ? maximum : tot; return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.ServiceUnavailable)); }
private static byte[] GetQuizMessage(BigInteger quizID) { byte[] quizData = GetQuiz(quizID); if (quizData.Length != 0) { Quiz quiz = Bytes2Quiz(quizData); byte[] message = Op.String2Bytes(quiz.message); return(NuTP.RespDataSucWithBody(message)); } return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.NotFound)); }
/** Forge a card with some score. With higher score, it may get higher chance make it better */ public static byte[] Forge(Credential credential, BigInteger cardId, BigInteger score) { if (Global.VerifyUser(credential)) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.ServiceUnavailable)); } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
/** User migrate to another server. * 玩家转服 * Return: bool for success/failure */ private static byte[] Migrate(Credential credential, BigInteger serverId) { if (Global.VerifyUser(credential)) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.ServiceUnavailable)); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Unauthorized));; } }
/** User (of email) claims the prizes * email对应用户领取占领奖励 * Return: An object of War. If failed to create, return null */ public static byte[] Claim(Credential credential, string email) { if (Global.VerifyUser(credential)) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.ServiceUnavailable)); } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
public static byte[] SetWeather(byte[] weathers) { if (Runtime.CheckWitness(Owner)) { RW.SaveWeathers(weathers); return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Forbidden)); } }
public static byte[] Genesis(BigInteger serverID) { if (Runtime.CheckWitness(Owner)) { Alg.GenesisCreateCities(serverID); //RW.GenesisCreateFake return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
/** User starts a war against a city. If the city is empty now, it's gonna occupy it directly. * 参战某城市, * Return: An object of War. If failed to create, return null */ /** User starts a war against a city. If the city is empty now, it's gonna occupy it directly. * 参战某城市, * Return: An object of War. If failed to create, return null */ public static byte[] StartSiege(Credential credential, BigInteger serverId, BigInteger cityId, byte[] cardIds) { if (Global.VerifyUser(credential)) { if (cityId >= Const.numCities) { return(NuTP.RespDataWithCode(ErrCate.City, ErrType.NotExist)); } else { //City does exist City city = RW.FindCity(serverId, cityId); BigInteger status = RW.GetStatusCity(city); if (status == StatusCity.Sieging) { return(NuTP.RespDataWithCode(ErrCate.City, ErrType.Duplicated)); } else { User user = RW.FindUser(credential.email); if (user.warID != Op.Void()) { //User does not allow to participate into multiple wars at the same time return(NuTP.RespDataWithCode(ErrCate.War, ErrType.Duplicated)); } else { CarryBattleSC.Card[] cards = RW.Table2Cards(cardIds); if (cards.Length != Const.numCardsSiege) { //Format of card array must be wrong return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } for (int i = 0; i < Const.numCardsSiege; i++) { if (cards[i].ownerEmail != user.email) { return(NuTP.RespDataWithCode(ErrCate.Card, ErrType.NotExist)); } } Siege siege = RW.CreateSiege(serverId, city, user, cards, Blockchain.GetHeight()); return(NuTP.RespDataSucWithBody(RW.Seige2Bytes(siege))); } } } } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
/** The Logic of merging the cards. The rule is: * 0. Two cards has to share the same owner * 1. Card1 has higher level than Card2 * 2. Card1 and Card2 should have the same */ public static byte[] CardMerge(byte[] cardID1, byte[] cardID2, string name) { Card card1 = ReadCard(cardID1); if (card1 == null) { return(NuTP.RespDataWithDetail(Error.Dom, Error.NoExist, Op.Bytes2String(cardID1), Op.Void())); } Card card2 = ReadCard(cardID2); if (card2 == null) { return(NuTP.RespDataWithDetail(Error.Dom, Error.NoExist, Op.Bytes2String(cardID2), Op.Void())); } if (Op.Bytes2BigInt(card1.ownerId) != Op.Bytes2BigInt(card2.ownerId)) { return(NuTP.RespDataWithCode(Error.Dom, Error.DiffOwner)); } if (card1.level >= card2.level) { BigInteger newLevel = card1.level + card2.level; Card newCard = new Card { id = Hash256(Op.JoinTwoByteArray(card1.id, card2.id)), name = name, level = newLevel, birthBlock = Blockchain.GetHeight(), ownerId = card1.ownerId, isLive = true }; SaveCard(newCard); card1.isLive = false; card2.isLive = false; SaveCard(card1); SaveCard(card2); return(NuTP.RespDataSucWithBody(Card2Bytes(newCard))); } else { return(NuTP.RespDataWithCode(Error.Dom, Error.LvInvalid)); } }
public static Object Main(string operation, params object[] args) { if (operation == "genesis") { return(Genesis()); } if (operation == "upgrade") { return(Upgrade((byte[])args[0], (BigInteger)args[1])); } if (operation == "collect") { return(Collect((byte[])args[0], (BigInteger)args[1], (byte[])args[2])); } return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.NotFound)); }
/* * NuTP: * * <RegCards> = [S<header>, S[S<card>*]] * */ private static byte[] RegCards(Credential credential, int num) { byte[] userData = RW.FindDataUser(credential.email); if (userData.Length == 0) { //Account Not exist return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.NotExist)); } else { //Account does exist User user = RW.Bytes2User(userData); int numAlready = RW.NumCardsOfUser(user); int numPending = Const.numCardsTotalReg - numAlready; if (numPending <= 0) { return(NuTP.RespDataWithCode(ErrCate.Card, ErrType.Duplicated)); } else { CarryBattleSC.Card[] cardsNew = GenerateRandomCards(user, (numPending < Const.numCardsPerReg) ? numPending : Const.numCardsPerReg); CarryBattleSC.Card[] cardsOrig = user.cards; user.cards = new CarryBattleSC.Card[cardsOrig.Length + cardsNew.Length]; for (int i = 0; i < cardsOrig.Length; i++) { user.cards[i] = cardsOrig[i]; } for (int j = 0; j < cardsNew.Length; j++) { user.cards[j + cardsOrig.Length] = cardsNew[j]; } //更新玩家数据 RW.SaveUser(user); byte[] body = RW.UserCards2Table(user); return(NuTP.RespDataSucWithBody(body)); } } }
/** * After 2nd stage finished, anybody can query the winnerPick. */ public static byte[] CalcResult(BigInteger gameId) { Game game = GetGame(gameId); if (game == null) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } else { if (game.winnerPick[0] == 1) { return(NuTP.RespDataSucWithBody(game.winnerPick)); } else { BigInteger height = Blockchain.GetHeight(); if (height < game.heightStage2) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Forbidden)); } else { BigInteger salt = 0; for (int i = 0; i < game.numEntries; i++) { Entry entry = GetEntry(gameId, i); if (entry.hidden.Length != 0) { salt += Op.Bytes2BigInt(entry.hidden); } } byte[] winnerPick = Op.SubBytes(Hash256(salt.ToByteArray()), 0, 1); game.winnerPick = winnerPick; return(NuTP.RespDataSucWithBody(winnerPick)); } } } }
private static byte[] FakeOccupies(BigInteger serverId, string email, BigInteger cityID) { if (Runtime.CheckWitness(Owner)) { if (cityID > Const.numCities || cityID <= 0) { return(NuTP.RespDataWithCode(ErrCate.City, ErrType.NotExist)); } else { User user = RW.FindUser(email); if (user != null) { City city = RW.FindCity(serverId, cityID); if (city.ownerID.Length == 0 || city.ownerID.Length == 1) //something wrong with bytes2string/string2bytes { //not work when it's not occupied city.ownerID = email; RW.SaveCity(serverId, city); user.city = cityID; RW.SaveUser(user); return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(ErrCate.City, ErrType.Duplicated)); } } else { return(NuTP.RespDataWithCode(ErrCate.User, ErrType.NotExist)); } } } else { return(NuTP.RespDataWithCode(ErrCate.Account, ErrType.AuthFail)); } }
public static byte[] IsWinner(BigInteger gameId, BigInteger entryId) { Game game = GetGame(gameId); if (game == null) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } else { BigInteger height = Blockchain.GetHeight(); if (height < game.heightStage2) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Forbidden)); } else { Entry entry = GetEntry(gameId, entryId); bool ret = entry.pick == game.winnerPick; return(NuTP.RespDataSucWithBody(Op.Bool2Bytes(ret))); } } }
/** * In the 2nd stage of each game, players submit the hidden number(prove), nobody can fake it * since it must match the hash every player submitted in during first round. * If a user failed to submit the prove, s/he will be elimiated from this game. */ public static byte[] PutProve(BigInteger gameId, BigInteger entryId, byte[] hidden) { Entry entry = GetEntry(gameId, entryId); Game game = GetGame(gameId); BigInteger height = Blockchain.GetHeight(); if (height < game.heightStage1 || height > game.heightStage2) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Forbidden)); } else { if (Hash256(hidden) == entry.hiddenHash) { entry.hidden = hidden; return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } } }
//唯有特权帐户允许从NASDAQ收盘价格读取数据后更新新增Pimetal的布置 //在同一周期里对每种丕料pimetalId可以有invokeTime次调用或修改(如果错误的话) public static byte[] AllocatePimetal(BigInteger pimetalId, BigInteger invokeTime) { if (Runtime.CheckWitness(Owner)) { BigInteger yearNext = GetYear() + 1; Transaction tx = (Transaction)ExecutionEngine.ScriptContainer; byte[] thisData = tx.Hash; //使用TxId生成随机数 int startIndex = (int)invokeTime * thisData.Length; byte[] totalData = NuIO.GetStorageWithKeyPath(keyPimetal, Op.BigInt2String(pimetalId)); byte[] startData = Op.SubBytes(totalData, 0, startIndex); byte[] endData = Op.SubBytes(totalData, startIndex + thisData.Length, totalData.Length - startIndex - thisData.Length); byte[] newData = Op.JoinByteArray(startData, thisData, endData); NuIO.SetStorageWithKeyPath(newData, keyPimetal, Op.BigInt2String(pimetalId)); return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.Unauthorized)); } }
public static object Main(string operation, params object[] args) { if (operation == "test") { byte o3 = 1; byte b3 = 12; byte e3 = 252; byte[] ba3 = new byte[3] { o3, b3, e3 }; // byte[] ba3 = new byte[3]{0,12,252}; Runtime.Notify(3, o3, b3, e3, ba3); byte o4 = 1; byte b4 = 12; byte e4 = 252; byte[] ba4 = new byte[3] { o4, b4, e4 }; // byte[] ba4 = new byte[3]{0,12,252}; Runtime.Notify(3, o4, b4, e4, ba4); return(true); } if (Runtime.Trigger == TriggerType.Verification) { if (Owner.Length == 20) { return(Runtime.CheckWitness(Owner)); } else if (Owner.Length == 33) { byte[] signature = Op.String2Bytes(operation); return(VerifySignature(signature, Owner)); } return(true); } else if (Runtime.Trigger == TriggerType.Application) { if (operation == Const.operationGenesis) { BigInteger serverId = (BigInteger)args[0]; return(Genesis(serverId)); } else if (operation == Const.operationFakeUsers) { // <emails> = [S<email>*] //<FakeUsers> = [S<user>*] BigInteger serverId = (BigInteger)args[0]; byte[] emails = (byte[])args[1]; return(FakeUsers(serverId, emails)); } else if (operation == Const.operationFakeOccupied) { //<FakeOccupies> = S<user> BigInteger serverId = (BigInteger)args[0]; string email = (string)args[1]; BigInteger cityId = (BigInteger)args[2]; return(FakeOccupies(serverId, email, cityId)); } else if (operation == Const.operationSetWeather) { byte[] weathers = (byte[])args[0]; return(SetWeather(weathers)); } else { string email = (string)args[0]; string psw = (string)args[1]; byte[] address = (byte[])args[2]; Credential credential = GenCred(email, address, psw); //<register> = S<header> if (operation == Const.operationRegister) { BigInteger serverId = (BigInteger)args[3]; string nickName = (string)args[4]; BigInteger iconID = (BigInteger)args[5]; return(Register(credential, serverId, nickName, iconID)); } //<regCards> = [S<header>,S<user>,S[S<cards>*]] if (operation == Const.operationRegCards) { BigInteger num = (BigInteger)args[3]; return(RegCards(credential, (int)num)); } if (operation == Const.operationMigrate) { BigInteger newServerId = (BigInteger)args[3]; return(Migrate(credential, newServerId)); } //<getUsers> = [S<header>,S<user>,S[S<cards>*]] if (operation == Const.operationGetUser) { string emailU = (string)args[3]; return(GetUser(credential, emailU)); } //<getUsers> = [S<header>,S<user>,S[S<cards>*]] if (operation == Const.operationGetUsers) { byte[] emails = (byte[])args[3]; return(GetUsers(credential, emails)); } if (operation == Const.operationgetCities) { BigInteger serverId = (BigInteger)args[3]; return(GetCities(credential, serverId)); } if (operation == Const.operationGetUserSeiges) { string userEmail = (string)args[3]; BigInteger max = (BigInteger)args[4]; return(GetUserSeiges(credential, userEmail, max)); } if (operation == Const.operationGetCitySeiges) { BigInteger serverId = (BigInteger)args[3]; BigInteger cityId = (BigInteger)args[4]; BigInteger max = (BigInteger)args[5]; return(GetCitySeiges(credential, serverId, cityId, max)); } if (operation == Const.operationSiege) { BigInteger serverId = (BigInteger)args[3]; BigInteger cityId = (BigInteger)args[4]; byte[] cardIds = (byte[])args[5]; return(StartSiege(credential, serverId, cityId, cardIds)); } if (operation == Const.operationClain) { string userEmail = (string)args[3]; return(Claim(credential, userEmail)); } if (operation == Const.operationForge) { BigInteger cardId = (BigInteger)args[3]; BigInteger score = (BigInteger)args[4]; return(Forge(credential, cardId, score)); } } } return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.NotFound)); }
public static byte[] Collect(byte[] invoker, BigInteger type, byte[] location) { byte[] invalidLoc = new byte[4] { 0, 0, 0, 0 }; if (location == invalidLoc) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } int typePimetal = 99; for (int i = 0; i < 3; i++) { byte[] locs = NuIO.GetStorageWithKeyPath(keyPimetal, Op.BigInt2String(type)); //byte[] locs = Storage.Get(Storage.CurrentContext, keyPimetal + i); for (int j = 0; j < locs.Length; j += 4) { if (locs[j] == location[0] && locs[j + 1] == location[1] && locs[j + 2] == location[2] && locs[j + 3] == location[3]) { typePimetal = i; //更新该处内存为00 byte[] newData = new byte[0]; for (int k = 0; k < locs.Length; k++) { if (k < j || k >= j + 3) { byte[] newVal = new byte[1] { locs[k] }; newData = Op.JoinTwoByteArray(newData, newVal); //newData = newData.Concat(newVal); } else if (k < j + 3) { byte[] newVal = new byte[1] { 0 }; newData = Op.JoinTwoByteArray(newData, newVal); } } NuIO.SetStorageWithKeyPath(newData, keyPimetal, Op.BigInt2String(typePimetal)); break; } } } Player player = FindPlayer(invoker); if (typePimetal == 99) { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); //非法输入值 } if (typePimetal == Pimetal.Water) { player.water += 1; } else if (typePimetal == Pimetal.Soil) { player.soil += 1; } else if (typePimetal == Pimetal.Wind) { player.wind += 1; } else if (typePimetal == Pimetal.Fire) { player.fire += 1; } byte[] newPlayerData = Player2Bytes(player); NuIO.SetStorageWithKeyPath(newPlayerData, keyPimetal, Op.BigInt2String(typePimetal)); return(NuTP.RespDataSuccess()); }
public static byte[] Upgrade(byte[] invoker, BigInteger feature) { Player player = FindPlayer(invoker); BigInteger lvl = -1; if (feature == 0) { lvl = player.lvlAtk; } else if (feature == 1) { lvl = player.lvlDef; } else if (feature == 2) { lvl = player.lvlSpd; } else if (feature == 3) { lvl = player.lvlHP; } else if (feature == 4) { lvl = player.lvlRev; } int f = Op.BigInt2Int(feature); BigInteger[] pimetals = AmountUpgrade(f, lvl + 1); if (player.water >= pimetals[0] && player.soil >= pimetals[1] && player.wind >= pimetals[2] && player.fire >= pimetals[3]) { player.water -= pimetals[0]; player.soil -= pimetals[1]; player.wind -= pimetals[2]; player.fire -= pimetals[3]; if (feature == 0) { player.lvlAtk += 1; } else if (feature == 1) { player.lvlDef += 1; } else if (feature == 2) { player.lvlSpd += 1; } else if (feature == 3) { player.lvlHP += 1; } else if (feature == 4) { player.lvlRev += 1; } return(NuTP.RespDataSuccess()); } else { return(NuTP.RespDataWithCode(NuTP.SysDom, NuTP.Code.BadRequest)); } }