Advertisement
payk

brick bronze server spawn scritp

Aug 9th, 2017
13,977
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 44.72 KB | None | 0 0
  1. -- OVH add a uniqueId to each mon sent to client for corresponding in things like part order switching, using items, etc.
  2. -- uid is unique to visit/may even change during visit (e.g. deposit/withdraw)
  3.  
  4. -- OVH: [SERVER]POKEMON OBJECTS MUST NOW BE DESTROYED
  5. -- Sanity check: I don't believe the above statement is entirely true. Perhaps they don't need to be destroyed; the server
  6. -- has a reference to them only when they are needed. Sure, they always retain a reference to the PlayerData
  7. -- itself, but if the PlayerData has a way of being destroyed (e.g. when a player leaves) then the Pokemon
  8. -- don't really need to be destroyed.
  9.  
  10. -- todo:
  11. -- getData functions
  12. -- evolve
  13. -- learn moves
  14. local _f = require(script.Parent)
  15.  
  16. local storage = game:GetService('ServerStorage')
  17.  
  18. local Utilities = _f.Utilities--require(storage.Utilities)
  19. local BitBuffer = _f.BitBuffer--require(storage.Plugins.BitBuffer)
  20.  
  21. local illegalPokemon = '\n' .. require(storage.Data.IllegalPokemon):gsub('\n0\n','\n') .. '\n'
  22. local whitelist = {}
  23. for _, id in pairs({
  24. 1123551, --'lando64000',
  25. 9739679, --'OldGoldie',
  26. 5665260, --'0AU',
  27. 747409, --'briest',
  28. 1084073, --'tbradm',
  29. 47791115,--'Tremity',
  30. 21632574,--'MySixthSense',
  31. 1281876, --'chrissuper',
  32. 32652184,--'Phyclops',
  33. 1560128, --'Srybon',
  34. 13094490,--'Lilly_S',
  35. 19053090,--'TigerCaptain',
  36. -- 'Player', 'Player1'
  37. 5730064, --'Kmansong2',
  38. 3651386, --'Anidave',
  39. 4189809, --'Our_Hero',
  40. 28276317,--'DVDKO',
  41. 75883152,--'VoidNex',
  42. 1283543, --'JamiyJamie',
  43. 4434374, --'Parlus',
  44. 84608682,--'DominoKid123',
  45. 8194465, --'Golden_God',
  46. 87895383,--'NeverMeltingIce',
  47. 23801047,--'Aife',
  48. }) do whitelist[id] = true end
  49.  
  50.  
  51. -- OVH redo these?
  52. local function getPokedexData(id, forme)
  53. return _f.DataService.fulfillRequest(nil, {'Pokedex', id, forme})
  54. end
  55.  
  56. local function getMoveData(id) -- lookin' great, have the rest follow suit
  57. if type(id) == 'number' then
  58. return _f.Database.MoveByNumber[id]
  59. end
  60. return _f.Database.MoveById[id]
  61. end
  62.  
  63. local function getItemData(id)
  64. if type(id) == 'number' then
  65. return _f.Database.ItemByNumber[id]
  66. end
  67. return _f.Database.ItemById[id]
  68. end
  69.  
  70. -- todo: pokerus + serialization
  71. local Pokemon
  72. Pokemon = Utilities.class({
  73. className = 'ServerPokemon',
  74.  
  75. balls = {
  76. 'pokeball',
  77. 'greatball',
  78. 'ultraball',
  79. 'masterball',
  80. 'colorlessball',--'safariball',
  81. 'insectball',--'levelball',
  82. 'dreadball',--'lureball',
  83. 'dracoball',--'moonball',
  84. 'zapball',--'friendball',
  85. 'fistball',--'loveball',
  86. 'flameball',--'heavyball',
  87. 'skyball',-- 'fastball',
  88. 'spookyball',--'sportball',
  89. 'premierball',
  90. 'repeatball',
  91. 'meadowball',--'timerball',
  92. 'earthball',--'nestball',
  93. 'netball',
  94. 'diveball',
  95. 'luxuryball',
  96. 'icicleball',--'healball',
  97. 'quickball',
  98. 'duskball',
  99. 'cherishball',
  100. 'toxicball',--'parkball',
  101. 'mindball',--'dreamball',
  102. 'stoneball',
  103. 'steelball',
  104. 'splashball',
  105. 'pixieball',
  106. 'pumpkinball',-- 31 (1 more allowed, but would have to correspond to [0])
  107. }
  108. }, function(self, PlayerData)--, ignoreLegality)
  109. self.PlayerData = PlayerData
  110. self.flags = {}
  111. if not self.personality then
  112. self.personality = math.floor(2^32 * math.random())
  113. end
  114.  
  115. local data = self:getData()
  116. if not self.name then
  117. self.name = data.baseSpecies or data.species
  118. end
  119. if not self.num then self.num = data.num end
  120. self.data = data
  121.  
  122. if --[[not ignoreLegality and]] self:isIllegal() then
  123. print('illegal pokemon', self.num)
  124. self.PlayerData.hasIllegalPokemon = true
  125. spawn(function() _f.DocIllegal(self.PlayerData.player, self.num) end)
  126. end
  127.  
  128. if self.egg and not self.eggCycles then
  129. self.eggCycles = data.eggCycles
  130. end
  131.  
  132. if self.shinyChance then
  133. local sc = self.shinyChance
  134. self.shinyChance = nil
  135. if PlayerData:ownsGamePass('ShinyCharm', true) then
  136. sc = math.floor(sc/2)
  137. end
  138. if PlayerData:ROPowers_getPowerLevel(5) >= 1 then
  139. sc = math.floor(sc/16)
  140. end
  141. local r = PlayerData:random(sc)-1
  142. local i = PlayerData.userId%sc
  143. if r == i then
  144. self.shiny = true
  145. end
  146. -- if _p.debug then
  147. -- print('New ' .. self.name .. '; shiny chance (1/' .. tostring(sc) .. '); r: ' .. tostring(r) .. ' i: ' .. tostring(i))
  148. -- end
  149. end
  150.  
  151. if not self.level then
  152. if self.experience then
  153. self.level = self:getLevelFromExperience()
  154. else
  155. self.level = 1
  156. end
  157. end
  158. self.experience = self.experience or self:getRequiredExperienceForLevel(self.level)
  159.  
  160. if not self.ivs then
  161. local ivs = {0, 0, 0, 0, 0, 0}
  162. for i = 1, 6 do
  163. ivs[i] = math.random(0, 31)
  164. end
  165. if not data.eggGroups then -- Undiscovered
  166. local s = {1, 2, 3, 4, 5, 6}
  167. for _ = 1, 3 do
  168. local stat = table.remove(s, math.random(#s))
  169. ivs[stat] = 31
  170. end
  171. end
  172. self.ivs = ivs
  173. end
  174. if not self.evs then
  175. self.evs = {0, 0, 0, 0, 0, 0}
  176. end
  177.  
  178. if not self.gender then
  179. local gr = data.genderRate or 127
  180. if gr < 254 and self.personality%256 >= gr then
  181. self.gender = 'M'
  182. elseif gr ~= 255 then
  183. self.gender = 'F'
  184. end
  185. end
  186.  
  187. if not self.nature then
  188. self.nature = (math.random(25)+math.floor(tick()*100))%25 + 1
  189. end
  190.  
  191. self:calculateStats() -- OVH is this even necessary any more? -> IT'S NEEDED FOR .hp / .maxhp; perhaps should remove other stats from fn
  192.  
  193. if self.moves then
  194. -- filter move duplicates, because a glitch once allowed duplication
  195. local moves = self.moves
  196. local known = {}
  197. for i = #moves, 1, -1 do
  198. local moveId = moves[i].id
  199. if known[moveId] then
  200. table.remove(moves, i)
  201. else
  202. known[moveId] = true
  203. end
  204. end
  205. else
  206. local learnedMoves = self:getLearnedMoves()
  207. if not learnedMoves or not learnedMoves.levelUp then
  208. print('learned moves not found for '..Utilities.toId(self.name))
  209. else
  210. local moves = {}
  211. for _, d in pairs(learnedMoves.levelUp) do
  212. if self.level < d[1] then break end
  213. for i = 2, #d do
  214. table.insert(moves, d[i])
  215. end
  216. end
  217. local known = {}
  218. for i = #moves, 1, -1 do
  219. local num = moves[i]
  220. if known[num] then
  221. table.remove(moves, i)
  222. else
  223. known[num] = true
  224. end
  225. end
  226. while #moves > 4 do
  227. table.remove(moves, 1)
  228. end
  229. for i, num in pairs(moves) do
  230. moves[i] = {id = getMoveData(num).id}
  231. end
  232. self.moves = moves
  233. end
  234. end
  235.  
  236. if not self.happiness then
  237. self.happiness = data.baseHappiness or 0
  238. end
  239.  
  240. return self
  241. end)
  242.  
  243. function Pokemon:getData()
  244. if (self.name == 'Meowstic' or self.num == 678) and self.personality%256 < 127 then
  245. -- is female meowstic; get specific data for female forme
  246. return getPokedexData('meowsticf')
  247. elseif self.name == 'Pumpkaboo' or self.num == 710 then
  248. return getPokedexData('pumpkaboo' .. (self:getFormeId() or ''))
  249. elseif self.name == 'Gourgeist' or self.num == 711 then
  250. return getPokedexData('gourgeist' .. (self:getFormeId() or ''))
  251. elseif self.num and not self.forme then
  252. return _f.Database.PokemonByNumber[self.num] -- OVH ideal, need to somehow convert everything else to follow the same pattern
  253. end
  254. return getPokedexData(self.name and Utilities.toId(self.name) or self.num, self.forme)
  255. end
  256.  
  257.  
  258. -- client requests
  259. function Pokemon:getPartyData(bp, context) -- OVH consider adding the uid
  260. if self.fossilEgg then
  261. return {
  262. fossilEgg = true, egg = true,
  263. name = 'Fossilized Egg',
  264. icon = self:getIcon()
  265. }
  266. elseif self.egg then
  267. return {
  268. egg = true,
  269. name = 'Egg',
  270. icon = self:getIcon()
  271. }
  272. end
  273. local item = self:getHeldItem()
  274. local data = {
  275. name = self:getName(),
  276. icon = bp.iconOverride or self:getIcon(),
  277. shiny = self.shiny,
  278. level = bp.level or self.level,
  279. hp = bp.hp or self.hp,
  280. maxhp = bp.maxhp or self.maxhp,
  281. status = bp.status or self.status, -- if bp exists then status (in battle) should be '' when nothing (therefore it will dominate, which is what we want)
  282. itemIcon = item.icon or item.num,
  283. gender = (self.data.num ~= 29 and self.data.num ~= 32 and self.gender) or nil,
  284. bindex = bp.index
  285. }
  286. if context == 'bag' and item.id then
  287. data.itemId = item.id
  288. data.itemName = item.name
  289. end
  290. if not self.PlayerData:isInBattle() and _f.Context == 'adventure' then
  291. local um
  292. local usable = {fly = true}
  293. for _, move in pairs(self:getMoves()) do
  294. if usable[move.id] then
  295. um = um or {}
  296. table.insert(um, move.id)
  297. end
  298. end
  299. if um then data.um = um end
  300. end
  301. return data
  302. end
  303.  
  304. function Pokemon:getSummary(bp)
  305. if self.fossilEgg then
  306. return {
  307. fossilEgg = true, egg = true,
  308. name = 'Fossilized Egg',
  309. eggStage = 1,
  310. icon = 1370
  311. }
  312. elseif self.egg then
  313. return {
  314. egg = true,
  315. name = 'Egg',
  316. eggStage = (self.eggCycles < 5) and 3 or ((self.eggCycles < 10) and 2 or 1),
  317. icon = self:getIcon() -- OVH summary should know to check if egg, and render using icon instead of spriteData
  318. }
  319. end
  320. local level = self.level
  321. local moves = {}
  322. for i, move in pairs(bp.moveset or self.moves) do
  323. moves[i] = {
  324. id = move.id,
  325. pp = move.pp,
  326. maxpp = move.maxpp,
  327. }
  328. end
  329. local movesData = self:getMoves() -- for properly calculated PP Ups
  330. for i, move in pairs(moves) do
  331. local moveData = movesData[i]--getMoveData(move.id)
  332. if not move.maxpp then move.maxpp = moveData.maxpp end
  333. if not move.pp then move.pp = move.maxpp end
  334. for _, prop in pairs({'accuracy','basePower','category','name','type','desc'}) do
  335. move[prop] = moveData[prop]
  336. end
  337. move.id = nil
  338. end
  339. local ballIcon
  340. pcall(function()
  341. local ball = _f.Database.ItemById[self:getPokeBall()]
  342. ballIcon = ball.icon or ball.num
  343. end)
  344.  
  345. local data = {
  346. num = self.data.num,
  347. name = self.name,
  348. nickname = self:getName(),
  349. ballIcon = ballIcon,
  350. status = bp.status or self.status, -- same as above comment about bp.status
  351. hp = bp.hp or self.hp,
  352. maxhp = bp.maxhp or self.maxhp,
  353. stats = self:getStats(bp.level, bp.baseStatOverride),
  354. nature = self.nature,
  355. itemName = self:getHeldItem().name, -- override in battle? meh...
  356. abilityName = bp.abilityOverride or self:getAbilityName(),
  357. gender = self.gender,
  358. level = bp.level or level,
  359. sprite = bp.frontSpriteOverride or self:getSprite(true),
  360. shiny = self.shiny,
  361. types = bp.typeOverride or self:getTypeNums(),
  362. id = math.max(0, self.ot or self.PlayerData.userId),
  363. desc = self:getCharacteristic(),
  364. moves = moves,
  365.  
  366. evs = self.evs,
  367. bss = self.data.baseStats
  368. }
  369. if not bp.forceHideStats and (bp.forceShowStats or self.PlayerData:ownsGamePass('StatViewer', true)) then
  370. data.ivs = self.ivs
  371. end
  372. if not bp.level or bp.level == level then
  373. local exp = self.experience
  374. local cl = self:getRequiredExperienceForLevel(level)
  375. local nl = self:getRequiredExperienceForLevel(level+1)
  376. data.exp = exp
  377. data.expToNx = level==100 and 0 or (nl - exp)
  378. data.expProg = level==100 and 0 or ((exp-cl) / (nl-cl))
  379. end
  380. return data
  381. end
  382. --
  383.  
  384.  
  385. function Pokemon:isIllegal(num)
  386. if whitelist[self.PlayerData.userId] then return false end
  387. return (illegalPokemon:find('\n'..(num or self.num)..'\n')) ~= nil
  388. end
  389.  
  390. function Pokemon:getName()
  391. if self.fossilEgg then
  392. return 'Fossilized Egg'
  393. elseif self.egg then
  394. return 'Egg'
  395. end
  396. return self.nickname or self.name
  397. end
  398.  
  399. function Pokemon:getSprite(front)
  400. local spriteId = self.name
  401. local formeId = self:getFormeId()
  402. if formeId and not self.data.normalSprite then
  403. spriteId = spriteId .. '-' .. formeId
  404. end
  405. local kind = front and '_FRONT' or '_BACK'
  406. if self.shiny then
  407. kind = '_SHINY' .. kind
  408. end
  409. return _f.DataService.fulfillRequest(nil, {'GifData', kind, spriteId, self.gender=='F'}) -- OVH is this best?
  410. end
  411.  
  412. function Pokemon:getFormeId()
  413. -- Vivillon
  414. if self.num == 666 then
  415. if self.forme then
  416. return self.forme
  417. end
  418. local n = self.ot%18
  419. if n == 0 then return nil end
  420. return ({--[['meadow',]]'polar','tundra','continental','garden','elegant',
  421. 'icysnow','modern','marine','archipelago','highplains','sandstorm',
  422. 'river','monsoon','savanna','sun','ocean','jungle'})[n]
  423. -- Pumpkaboo / Gourgeist
  424. elseif self.num == 710 or self.num == 711 or self.name == 'Pumpkaboo' or self.name == 'Gourgeist' then
  425. if not self.forme then return nil end
  426. return ({
  427. s = 'small',
  428. L = 'large',
  429. S = 'super',
  430. })[self.forme]
  431. -- Flabebe / Floette / Florges
  432. elseif self.num == 669 or self.num == 670 or self.num == 671 then
  433. if not self.forme then return nil end
  434. return ({
  435. o = 'orange',
  436. y = 'yellow',
  437. w = 'white',
  438. b = 'blue',
  439. e = 'eternal',
  440. })[self.forme]
  441. -- Arceus
  442. elseif self.num == 493 then
  443. if not self.item then return nil end
  444. return ({
  445. insectplate = 'bug',
  446. dreadplate = 'dark',
  447. dracoplate = 'dragon',
  448. zapplate = 'electric',
  449. pixieplate = 'fairy',
  450. fistplate = 'fighting',
  451. flameplate = 'fire',
  452. skyplate = 'flying',
  453. spookyplate = 'ghost',
  454. meadowplate = 'grass',
  455. earthplate = 'ground',
  456. icicleplate = 'ice',
  457. toxicplate = 'poison',
  458. mindplate = 'psychic',
  459. stoneplate = 'rock',
  460. ironplate = 'steel',
  461. splashplate = 'water',
  462. })[self:getHeldItem().id]
  463. else
  464. return self.forme
  465. end
  466. end
  467.  
  468. local CHAT = game:GetService('Chat')
  469. function Pokemon:filterNickname(nickname, player)
  470. nickname = nickname:gsub('|', '')
  471. if not player then
  472. player = self.PlayerData.player
  473. end
  474. nickname = CHAT:FilterStringAsync(nickname, player, player)
  475. do
  476. local bytes = {string.byte(nickname, 1, #nickname)}
  477. for i = #bytes, 1, -1 do
  478. local b = bytes[i]
  479. if b < 32 or b > 126 then
  480. table.remove(bytes, i)
  481. end
  482. end
  483. nickname = string.char(unpack(bytes))
  484. end
  485. if nickname:len() > 12 then
  486. nickname = nickname:sub(1, 12)
  487. end
  488. return nickname
  489. end
  490.  
  491. function Pokemon:giveNickname(nickname)
  492. self.nickname = self:filterNickname(nickname)
  493. end
  494.  
  495.  
  496. -- Evolution/Learning Moves (decision packets)
  497. function Pokemon:getCurrentMovesData()
  498. local moves = {}
  499. for i, m in pairs(self.moves) do
  500. local move = _f.Database.MoveById[m.id]
  501. moves[i] = {
  502. name = move.name,
  503. category = move.category,
  504. type = move.type,
  505. power = move.basePower,
  506. accuracy = move.accuracy,
  507. pp = move.pp,
  508. desc = move.desc
  509. }
  510. end
  511. return moves
  512. end
  513.  
  514. function Pokemon:generateDecisionsForMoves(moves)
  515. if not moves then return end
  516. local decisions = {}
  517. for i, mnum in pairs(moves) do
  518. local move = _f.Database.MoveByNumber[mnum]
  519. -- print('move num', mnum)
  520. local decisionId = self.PlayerData:createDecision {
  521. callback = function(data, slot)
  522. if not slot then return end -- slot = nil means they choose not to learn it
  523. if type(slot) ~= 'number' or slot<1 or slot>4 or slot%1~=0 then return false end
  524. for _, m in pairs(self.moves) do -- be sure they don't already know the move
  525. if m.id == move.id then return false end
  526. end
  527. self.moves[slot] = {id = move.id}
  528. return true
  529. end
  530. }
  531. decisions[i] = {
  532. id = decisionId,
  533. move = {
  534. name = move.name,
  535. category = move.category,
  536. type = move.type,
  537. power = move.basePower,
  538. accuracy = move.accuracy,
  539. pp = move.pp,
  540. desc = move.desc
  541. }
  542. }
  543. end
  544. return decisions
  545. end
  546.  
  547. function Pokemon:generateEvolutionDecision(...)
  548. local evo, chi = self:getEligibleEvolution(...)
  549. if not evo then return end
  550. local baseEvolutionData = _f.Database.PokemonByNumber[evo]
  551.  
  552. local spriteDataBefore = self:getSprite(true)
  553. local numBefore, nameBefore = self.num, self.name
  554. self.num, self.name = baseEvolutionData.num, baseEvolutionData.species
  555.  
  556. local evolutionData = self:getData()
  557. local movesToLearn = self:getMovesLearnedAtLevel(self.level)
  558. local evolutionMove = self:getLearnedMoves().evolve
  559. if evolutionMove then
  560. if movesToLearn then
  561. table.insert(movesToLearn, 1, evolutionMove)
  562. else
  563. movesToLearn = {evolutionMove}
  564. end
  565. end
  566. local learnedMovesAfter = self:generateDecisionsForMoves(movesToLearn)
  567.  
  568. local spriteDataAfter = self:getSprite(true)
  569. self.num, self.name = numBefore, nameBefore
  570.  
  571. local decisionId = self.PlayerData:createDecision {
  572. callback = function(data, allow)
  573. if not allow then return end
  574. self:evolve(evolutionData, chi)
  575. end
  576. }
  577. return {
  578. decisionId = decisionId,
  579. name = evolutionData.species,
  580. nickname = self.nickname,
  581. sprite1 = spriteDataBefore,
  582. sprite2 = spriteDataAfter,
  583. moves = learnedMovesAfter,
  584. flip = (self.num == 686 and true or nil)
  585. }
  586. end
  587.  
  588. function Pokemon:getEligibleEvolution(trigger, isDay, triggerItem)
  589. if self.egg then return end
  590. local evolution = self.data.evolution or _f.Database.Evolution[self.num]
  591. if not evolution then return end
  592. if self.num == 670 and self.forme == 'e' then return end -- Floette Eternal forme does not evolve
  593. if self.num == 399 and self.forme == 'rainbow' then return end -- Rainbow Bidoof does not evolve
  594. if self.num == 25 and self.forme == 'heart' then return end -- Heart Pikachu does not evolve
  595. if (trigger == 1 or trigger == 2) and self:getHeldItem().id == 'everstone' then return end
  596.  
  597. local PlayerData = self.PlayerData
  598. for _, evo in pairs(evolution) do
  599. for _=1,1 do
  600. local consumeHeldItem = false
  601. if evo.evolution_trigger_id ~= trigger then break end
  602. if evo.trigger_item_id and triggerItem ~= evo.trigger_item_id then break end
  603. if evo.minimum_level and self.level < evo.minimum_level then break end
  604. if evo.gender_id == 1 and self.gender ~= 'F' then break end
  605. if evo.gender_id == 2 and self.gender ~= 'M' then break end
  606. if evo.location_id then
  607. local s, r
  608. if evo.location_id == 8 then -- Moss Rock; Leafeon
  609. s, r = pcall(function()
  610. return _f.Context == 'adventure' and
  611. PlayerData.currentChunk == 'chunk12' and
  612. ((PlayerData.player.Character.HumanoidRootPart.Position-Vector3.new(-628, 0, -276))*Vector3.new(1,0,1)).magnitude < 15
  613. end)
  614. elseif evo.location_id == 10 then -- ambiguous (Magneton/Nosepass)
  615. -- if self.num == 82 then -- Route 3; Magnezone
  616. s, r = pcall(function()
  617. return _f.Context == 'adventure' and
  618. PlayerData.currentChunk == 'chunk3' and
  619. PlayerData:getRegion() == 'Route 3'
  620. end)
  621. -- end
  622. end
  623. -- glaceon @ location 48
  624. if not s or not r then break end
  625. end
  626. if evo.held_item_id then
  627. if evo.held_item_id ~= self:getHeldItem().num then break end
  628. consumeHeldItem = true
  629. end
  630. if evo.time_of_day == 'day' and not isDay then break end
  631. if evo.time_of_day == 'night' and isDay then break end
  632. if evo.known_move_id then
  633. local hasMove = false
  634. for _, m in pairs(self:getMoves()) do
  635. if m.num == evo.known_move_id then
  636. hasMove = true
  637. break
  638. end
  639. end
  640. if not hasMove then break end
  641. end
  642. if evo.known_move_type_id == 18 then
  643. local hasMoveType = false
  644. for _, m in pairs(self:getMoves()) do
  645. if m.type == 'Fairy' then
  646. hasMoveType = true
  647. break
  648. end
  649. end
  650. if not hasMoveType then break end
  651. end
  652. if evo.minimum_happiness and self.happiness < evo.minimum_happiness then break end
  653. if evo.minimum_beauty then break end -- use Prism Scale instead
  654. if evo.minimum_affection then
  655. if self:getHeldItem().id ~= 'affectionribbon' then break end
  656. consumeHeldItem = true
  657. end
  658. if evo.relative_physical_stats then
  659. self:calculateStats()
  660. local relAtk = math.max(-1, math.min(1, self.stats.atk-self.stats.def))
  661. if relAtk ~= evo.relative_physical_stats then break end
  662. end
  663. if evo.party_species_id then
  664. local hasInParty = false
  665. -- todo
  666. if not hasInParty then break end
  667. end
  668. if evo.party_type_id == 17 then
  669. local hasTypeInParty = false
  670. for _, p in pairs(self.PlayerData.party) do
  671. if not p.egg then
  672. local types = p:getTypes()
  673. if types[1] == 'Dark' or types[2] == 'Dark' then
  674. hasTypeInParty = true
  675. break
  676. end
  677. end
  678. end
  679. if not hasTypeInParty then break end
  680. end
  681. if evo.trade_species_id then break end -- todo
  682. if evo.needs_overworld_rain then break end -- todo
  683. -- if evo.turn_upside_down then break end -- OVH TODO
  684. -- if not userInputService.AccelerometerEnabled then break end
  685. -- local a = self.orientationLastLevelup
  686. -- local b; pcall(function() b = userInputService:GetDeviceGravity().Position end)
  687. -- if not a or not b then self.orientationLastLevelup = nil break end
  688. -- a = (a*Vector3.new(1,0,1)).unit
  689. -- b = (b*Vector3.new(1,0,1)).unit
  690. -- if a.magnitude + b.magnitude < 1.9 then self.orientationLastLevelup = nil break end
  691. -- local angle = math.deg(math.acos(a:Dot(b)))
  692. -- if angle < 150 then self.orientationLastLevelup = nil break end
  693. -- end
  694.  
  695. if evo.evolved_species_id == 266 and math.floor(self.personality / 65536) % 10 >= 5 then break end
  696. if evo.evolved_species_id == 268 and math.floor(self.personality / 65536) % 10 < 5 then break end
  697.  
  698. -- passed all filters
  699. return evo.evolved_species_id, consumeHeldItem
  700. end
  701. end
  702. end
  703.  
  704. function Pokemon:evolve(evolutionData, consumeHeldItem)
  705. local PlayerData = self.PlayerData
  706. local movesCopy = Utilities.deepcopy(self.moves)
  707.  
  708. PlayerData:onOwnPokemon(evolutionData.num)
  709. if consumeHeldItem then
  710. self.item = nil
  711. end
  712. self.data = evolutionData
  713. self.name = evolutionData.species
  714. self.num = evolutionData.num
  715.  
  716. -- if in-battle, post-battle updates have already applied
  717. local hpMissing = self.maxhp - self.hp
  718. self:calculateStats()
  719. self.hp = self.maxhp - hpMissing
  720.  
  721. pcall(function()
  722. if self:isLead() then
  723. _f.Network:post('PDChanged', PlayerData.player, 'firstNonEggAbility', self:getAbilityName())
  724. end
  725. end)
  726.  
  727. -- Shedinja
  728. if self.num == 291 and #PlayerData.party < 6 and PlayerData:incrementBagItem('pokeball', -1) then
  729. table.insert(PlayerData.party, Pokemon:new({
  730. name = 'Shedinja',
  731. shiny = self.shiny,
  732. ivs = {self.ivs[1], self.ivs[2], self.ivs[3], self.ivs[4], self.ivs[5], self.ivs[6]},
  733. evs = { 0, self.evs[2], self.evs[3], self.evs[4], self.evs[5], self.evs[6]},
  734. personality = self.personality,
  735. level = self.level,
  736. experience = self.experience,
  737. ot = self.ot,
  738. moves = movesCopy,
  739. nature = self.nature,
  740. }, PlayerData))
  741. PlayerData:onOwnPokemon(292)
  742. end
  743. end
  744. --
  745.  
  746.  
  747. function Pokemon:getEVs()
  748. if self.evsFiltered then return self.evs end
  749. self.evsFiltered = true
  750. local totalEVs = 0
  751. local overflow = false
  752. for i = 1, 6 do
  753. local ev = self.evs[i]
  754. if ev > 252 then
  755. overflow = true
  756. end
  757. totalEVs = totalEVs + ev
  758. end
  759. if totalEVs > 510 then
  760. local ratio = 510 / totalEVs
  761. for i = 1, 6 do
  762. self.evs[i] = math.floor(self.evs[i] * ratio)
  763. end
  764. end
  765. if overflow then
  766. for i = 1, 6 do
  767. self.evs[i] = math.min(252, self.evs[i])
  768. end
  769. end
  770. return self.evs
  771. end
  772.  
  773. function Pokemon:getBattleData(ignoreHPState)
  774. -- self:calculateStats()
  775. local set = {}
  776. set.id = Utilities.toId(self.data.species)--self.data.id
  777. set.nickname = self.nickname
  778. set.level = self.level
  779. if not ignoreHPState then set.status = self.status end
  780. set.gender = self.gender or ''
  781. set.happiness = self.happiness or 0
  782. set.shiny = self.shiny
  783. set.stamps = self.stamps
  784. set.item = self:getHeldItem().id
  785. set.ability = self:getAbilityConfig()
  786. -- set.types = self:getTypes()
  787. set.moves = {}
  788. for i, m in pairs(self:getMoves()) do
  789. -- print(m.id)
  790. set.moves[i] = {
  791. id = m.id,
  792. pp = ignoreHPState and m.maxpp or m.pp,
  793. maxpp = m.maxpp,
  794. }
  795. end
  796. set.ivs = self.ivs
  797. set.evs = self:getEVs()
  798. set.nature = self:getNature().name
  799. if not ignoreHPState then set.hp = self.hp end
  800. if self.egg then
  801. set.hp = 0
  802. set.isEgg = true
  803. else
  804. set.forme = self:getFormeId()
  805. end
  806. set.isNotOT = (self.ot and self.PlayerData and self.ot ~= self.PlayerData.userId)
  807. -- set.pokerus = self.pokerus -- todo
  808. set.index = self:getPartyIndex()
  809. set.pokeball = self.pokeball
  810. return set
  811. end
  812.  
  813. function Pokemon:isLead()
  814. local lead = false
  815. pcall(function()
  816. if self.PlayerData:getFirstNonEgg() == self then
  817. lead = true
  818. end
  819. end)
  820. return lead
  821. end
  822.  
  823. function Pokemon:getPartyIndex()
  824. for i = 1, 6 do
  825. if self.PlayerData.party[i] == self then
  826. return i
  827. end
  828. end
  829. end
  830.  
  831. function Pokemon:getLearnedMoves()
  832. if self.num == 678 and self.gender == 'F' then
  833. return _f.Database.FemaleMeowsticLearnedMoves
  834. elseif self.num == 492 and self.forme == 'sky' then
  835. return _f.Database.ShayminSkyLearnedMoves
  836. elseif self.num == 484 and self.forme == 'dark' then
  837. return _f.Database.DarkPalkiaLearnedMoves
  838. elseif self.forme == 'Alola' then
  839. local moves = _f.Database.LearnedMoves.Alola[Utilities.toId(self.name)]
  840. if moves then
  841. return moves
  842. end
  843. end
  844. return _f.Database.LearnedMoves[self.num] or {}
  845. end
  846.  
  847. function Pokemon:getMovesLearnedAtLevel(level)
  848. local moves = self:getLearnedMoves()
  849. if not moves.levelUp then return end
  850. for _, md in pairs(moves.levelUp) do
  851. if md[1] == level then
  852. local list = {}
  853. for i = 2, #md do
  854. list[i-1] = md[i]
  855. end
  856. return list
  857. end
  858. end
  859. end
  860.  
  861. function Pokemon:forceLearnLevelUpMoves(startLevel, endLevel) -- used by daycare
  862. local s, r = pcall(function()
  863. local function learn(num)
  864. for _, m in pairs(self:getMoves()) do
  865. if num == m.num then return end
  866. end
  867. table.insert(self.moves, {id = getMoveData(num).id})
  868. while #self.moves > 4 do
  869. table.remove(self.moves, 1)
  870. end
  871. end
  872. for _, lm in pairs(self:getLearnedMoves().levelUp) do
  873. if lm[1] > endLevel then break end
  874. if lm[1] >= startLevel then
  875. for i = 2, #lm do
  876. learn(lm[i])
  877. end
  878. end
  879. end
  880. end)
  881. if not s then
  882. warn('error occurred while trying to force learn level up moves:')
  883. warn(r)
  884. end
  885. end
  886.  
  887. function Pokemon:calculateStats(withBaseStats)
  888. local data = self.data
  889. local bs = withBaseStats or data.baseStats
  890.  
  891. self.stats = {atk = 0, def = 0, spa = 0, spd = 0, spe = 0}
  892. local statIndices = {atk = 2, def = 3, spa = 4, spd = 5, spe = 6}
  893. local nature = self:getNature()
  894. for statName in pairs(self.stats) do
  895. local index = statIndices[statName]
  896. local stat = bs[index]
  897. stat = math.floor(math.floor(2 * stat + self.ivs[index] + math.floor(self.evs[index] / 4)) * self.level / 100 + 5)
  898. if statName == nature.plus then stat = stat * 1.1 end
  899. if statName == nature.minus then stat = stat * 0.9 end
  900. self.stats[statName] = math.floor(stat)
  901. end
  902.  
  903. self.maxhp = math.floor(math.floor(2 * data.baseStats[1] + self.ivs[1] + math.floor(self.evs[1] / 4) + 100) * self.level / 100 + 10)
  904. if bs[1] == 1 then self.maxhp = 1 end -- Shedinja
  905. self.hp = math.min(self.maxhp, self.hp or self.maxhp)
  906. end
  907.  
  908. function Pokemon:getStats(level, baseStats) -- returns 5-element array from ATK to SPEED (with HP excluded) for viewSummary requests
  909. local bs = baseStats or self.data.baseStats
  910. local stats = {0, 0, 0, 0, 0}
  911. local nature = self:getNature()
  912. local statNames = {'atk', 'def', 'spa', 'spd', 'spe'}
  913. for s = 2, 6 do
  914. local stat = bs[s]
  915. stat = math.floor(math.floor(2 * stat + self.ivs[s] + math.floor(self.evs[s] / 4)) * (level or self.level) / 100 + 5)
  916. local statName = statNames[s-1]
  917. if statName == nature.plus then stat = stat * 1.1 end
  918. if statName == nature.minus then stat = stat * 0.9 end
  919. stats[s-1] = math.floor(stat)
  920. end
  921. return stats
  922. end
  923.  
  924. function Pokemon:heal()
  925. self:calculateStats()
  926. self.hp = self.maxhp
  927. self.status = nil
  928. for i, m in pairs(self:getMoves()) do
  929. self.moves[i].pp = m.maxpp
  930. end
  931. end
  932.  
  933. do -- TODO: I don't think this function is even used...
  934. local players = game:GetService('Players')
  935. local usernameCache = {}
  936. function Pokemon:getOT()
  937. local pd = self.PlayerData
  938. local ot = self.ot
  939. if not ot or ot == pd.userId then return pd.player.Name, pd.userId end
  940. if ot <= 0 then
  941. return 'Guest', 0
  942. end
  943. local cachedName = usernameCache[ot]
  944. if cachedName then return cachedName, ot end
  945. local name
  946. local s = pcall(function() name = players:GetNameFromUserIdAsync(self.ot) end)
  947. -- if not s then
  948. -- print(self.ot)
  949. -- end
  950. usernameCache[ot] = name
  951. return name, self.ot
  952. end
  953. end
  954.  
  955. function Pokemon:getMoves()
  956. local moves = {}
  957. for i, m in pairs(self.moves) do
  958. if not m.id then
  959. warn('corrupt move found: '..self.name..'['..i..']')
  960. end
  961. local moveData = getMoveData(m.id)
  962. local maxpp = (m.ppup and moveData.pp>1) and math.floor(moveData.pp*(1+.2*m.ppup)) or moveData.pp
  963. moves[i] = {
  964. num = moveData.num,
  965. id = moveData.id,
  966. name = moveData.name,
  967. pp = m.pp or maxpp,
  968. maxpp = maxpp,
  969. type = moveData.type,
  970. basePower = moveData.basePower,
  971. accuracy = moveData.accuracy,
  972. desc = moveData.desc,
  973. category = moveData.category,
  974. }
  975. end
  976. return moves
  977. end
  978.  
  979. function Pokemon:getNature()
  980. local natures = {
  981. --[[01]]{name='Hardy' },
  982. --[[02]]{name='Lonely', plus='atk', minus='def'},
  983. --[[03]]{name='Brave', plus='atk', minus='spe'},
  984. --[[04]]{name='Adamant', plus='atk', minus='spa'},
  985. --[[05]]{name='Naughty', plus='atk', minus='spd'},
  986. --[[06]]{name='Bold', plus='def', minus='atk'},
  987. --[[07]]{name='Docile' },
  988. --[[08]]{name='Relaxed', plus='def', minus='spe'},
  989. --[[09]]{name='Impish', plus='def', minus='spa'},
  990. --[[10]]{name='Lax', plus='def', minus='spd'},
  991. --[[11]]{name='Timid', plus='spe', minus='atk'},
  992. --[[12]]{name='Hasty', plus='spe', minus='def'},
  993. --[[13]]{name='Serious' },
  994. --[[14]]{name='Jolly', plus='spe', minus='spa'},
  995. --[[15]]{name='Naive', plus='spe', minus='spd'},
  996. --[[16]]{name='Modest', plus='spa', minus='atk'},
  997. --[[17]]{name='Mild', plus='spa', minus='def'},
  998. --[[18]]{name='Quiet', plus='spa', minus='spe'},
  999. --[[19]]{name='Bashful' },
  1000. --[[20]]{name='Rash', plus='spa', minus='spd'},
  1001. --[[21]]{name='Calm', plus='spd', minus='atk'},
  1002. --[[22]]{name='Gentle', plus='spd', minus='def'},
  1003. --[[23]]{name='Sassy', plus='spd', minus='spe'},
  1004. --[[24]]{name='Careful', plus='spd', minus='spa'},
  1005. --[[25]]{name='Quirky' },
  1006. }
  1007. return natures[self.nature]
  1008. end
  1009.  
  1010. function Pokemon:addHappiness(a, b, c)
  1011. local mult = 1
  1012. if self:getPokeBall() == 'luxuryball' and a > 0 then
  1013. mult = 2
  1014. end
  1015. if self.happiness < 100 then
  1016. self.happiness = self.happiness + a * mult
  1017. elseif self.happiness < 200 then
  1018. self.happiness = self.happiness + (b or a) * mult
  1019. else
  1020. self.happiness = self.happiness + (c or b or a) * mult
  1021. end
  1022. self.happiness = math.max(0, math.min(255, self.happiness))
  1023. end
  1024.  
  1025. function Pokemon:getIcon(ignoreEgg)--::getIcon
  1026. local icon = self.data.icon-1
  1027. local alts = {['Unown-b'] =215-1,
  1028. ['Unown-c'] =216-1,
  1029. ['Unown-d'] =217-1,
  1030. ['Unown-e'] =218-1,
  1031. ['Unown-exclaim'] =219-1,
  1032. ['Unown-f'] =220-1,
  1033. ['Unown-g'] =221-1,
  1034. ['Unown-h'] =222-1,
  1035. ['Unown-i'] =223-1,
  1036. ['Unown-j'] =224-1,
  1037. ['Unown-k'] =225-1,
  1038. ['Unown-l'] =226-1,
  1039. ['Unown-m'] =227-1,
  1040. ['Unown-n'] =228-1,
  1041. ['Unown-o'] =229-1,
  1042. ['Unown-p'] =230-1,
  1043. ['Unown-q'] =231-1,
  1044. ['Unown-query'] =232-1,
  1045. ['Unown-r'] =233-1,
  1046. ['Unown-s'] =234-1,
  1047. ['Unown-t'] =235-1,
  1048. ['Unown-u'] =236-1,
  1049. ['Unown-v'] =237-1,
  1050. ['Unown-w'] =238-1,
  1051. ['Unown-x'] =239-1,
  1052. ['Unown-y'] =240-1,
  1053. ['Unown-z'] =241-1,
  1054. ['Victini-blue'] =886-1,
  1055. ['Volcanion-black']=890-1,
  1056. ['Haunter-hallow'] =892-1,
  1057. ['Gengar-hallow'] =893-1,
  1058. ['Mew-rainbow'] =1016-1,
  1059. ['Onix-crystal'] =1024-1,
  1060. ['Steelix-crystal']=1025-1}
  1061. if self.egg and not ignoreEgg then
  1062. if self.fossilEgg then
  1063. return 1820 -- egg threshold dependent
  1064. else
  1065. return 1450 + (self.data.eggIcon or 135) -- egg threshold
  1066. end
  1067. elseif self.num == 666 then
  1068. -- Vivillon
  1069. icon = icon + (({
  1070. archipelago = 1,
  1071. continental = 2,
  1072. elegant = 3,
  1073. fancy = 4,
  1074. garden = 5,
  1075. highplains = 6,
  1076. icysnow = 7,
  1077. jungle = 8,
  1078. marine = 9,
  1079. modern = 10,
  1080. monsoon = 11,
  1081. ocean = 12,
  1082. pokeball = 13,
  1083. polar = 14,
  1084. river = 15,
  1085. sandstorm = 16,
  1086. savanna = 17,
  1087. sun = 18,
  1088. tundra = 19,
  1089. })[self:getFormeId()] or 0)
  1090. elseif self.forme and (self.num == 669 or self.num == 670 or self.num == 671) then
  1091. -- Flabebe, Floette, Florges
  1092. if self.forme == 'e' then
  1093. icon = icon + 2
  1094. else
  1095. icon = icon + ({b=1,o=2,w=3,y=4})[self.forme]
  1096. if self.num == 670 and self.forme ~= 'b' then
  1097. icon = icon + 1
  1098. end
  1099. end
  1100. elseif self.forme and alts[self.name..'-'..self.forme] then
  1101. icon = alts[self.name..'-'..self.forme]
  1102. elseif self.gender == 'F' then
  1103. -- Unfezant, Frillish, Jellicent, Pyroar, Meowstic
  1104. if ({[598]=true,[678]=true,[680]=true,[782]=true,[815]=true})[icon+1] then -- TODO: HIPPOWDON
  1105. icon = icon + 1
  1106. end
  1107. end
  1108. return icon
  1109. end
  1110.  
  1111. function Pokemon:getCharacteristic()
  1112. local characteristics = {
  1113. { 'Loves to eat', 'Proud of its power', 'Sturdy body', 'Highly curious', 'Strong willed', 'Likes to run' },
  1114. { 'Takes plenty of siestas', 'Likes to thrash about', 'Capable of taking hits', 'Mischievous', 'Somewhat vain', 'Alert to sounds' },
  1115. { 'Nods off a lot', 'A little quick tempered', 'Highly persistent', 'Thoroughly cunning', 'Strongly defiant', 'Impetuous and silly' },
  1116. { 'Scatters things often', 'Likes to fight', 'Good endurance', 'Often lost in thought', 'Hates to lose', 'Somewhat of a clown' },
  1117. { 'Likes to relax', 'Quick tempered', 'Good perseverance', 'Very finicky', 'Somewhat stubborn', 'Quick to flee' },
  1118. }
  1119. local maxivs = {}
  1120. local maxiv = 0
  1121. for i = 1, 6 do
  1122. if self.ivs[i] > maxiv then
  1123. maxiv = self.ivs[i]
  1124. maxivs = {[i] = true}
  1125. elseif self.ivs[i] == maxiv then
  1126. maxivs[i] = true
  1127. end
  1128. end
  1129. local stat
  1130. local stats = {1, 2, 3, 6, 4, 5}
  1131. local p = self.personality%6+1
  1132. for i = p, 6 do
  1133. if maxivs[stats[i]] then
  1134. stat = stats[i]
  1135. break
  1136. end
  1137. end
  1138. if not stat then
  1139. for i = 1, p-1 do
  1140. if maxivs[stats[i]] then
  1141. stat = stats[i]
  1142. break
  1143. end
  1144. end
  1145. end
  1146. return characteristics[maxiv%5+1][stat]
  1147. end
  1148.  
  1149. function Pokemon:getTypeNums()
  1150. return self.data.types
  1151. end
  1152.  
  1153. function Pokemon:getTypes(fromTypes)
  1154. --[[ if self.num == 493 then
  1155. local forme = self:getFormeId()
  1156. if forme then
  1157. return {forme:sub(1,1):upper()..forme:sub(2)}
  1158. end
  1159. return {'Normal'}
  1160. end--]]
  1161. local typeFromInt = {'Bug','Dark','Dragon','Electric','Fairy','Fighting','Fire','Flying','Ghost','Grass','Ground','Ice','Normal','Poison','Psychic','Rock','Steel','Water'}
  1162. local types = {}
  1163. for i, t in pairs(fromTypes or self:getTypeNums()) do
  1164. types[i] = typeFromInt[t]
  1165. end
  1166. return types
  1167. end
  1168.  
  1169. function Pokemon:getAbilityName()
  1170. if self.hiddenAbility and self.data.hiddenAbility then
  1171. return self.data.hiddenAbility
  1172. elseif #self.data.abilities == 1 then
  1173. return self.data.abilities[1]
  1174. end
  1175. local a = math.floor(self.personality / 65536) % 2
  1176. if self.swappedAbility then a = 1-a end
  1177. return self.data.abilities[a+1]
  1178. end
  1179.  
  1180. function Pokemon:getAbilityConfig()
  1181. if self.hiddenAbility and self.data.hiddenAbility then
  1182. return 3
  1183. elseif #self.data.abilities == 1 then
  1184. return 1
  1185. end
  1186. local a = math.floor(self.personality / 65536) % 2
  1187. if self.swappedAbility then a = 1-a end
  1188. return a+1
  1189. end
  1190.  
  1191. function Pokemon:getHeldItem()--::getHeldItem
  1192. if not self.item then return {} end
  1193. return getItemData(self.item)
  1194. end
  1195.  
  1196. function Pokemon:getPokeBall(ballId)
  1197. return self.balls[ballId or self.pokeball or 1]
  1198. end
  1199.  
  1200. function Pokemon:getRequiredExperienceForLevel(lvl)
  1201. local rate = self.data.expRate or 2
  1202. if lvl == 1 then return 0 end
  1203. if rate == 0 then -- Erratic
  1204. if lvl <= 50 then
  1205. return math.floor(lvl^3 * (100-lvl) / 50)
  1206. elseif lvl <= 68 then
  1207. return math.floor(lvl^3 * (150-lvl) / 100)
  1208. elseif lvl <= 98 then
  1209. return math.floor(lvl^3 * math.floor((1911-10*lvl) / 3) / 500)
  1210. end
  1211. return math.floor(lvl^3 * (160-lvl) / 100)
  1212. elseif rate == 1 then -- Fast
  1213. return math.floor(lvl^3 * 4 / 5)
  1214. elseif rate == 2 then -- Medium Fast
  1215. return lvl^3
  1216. elseif rate == 3 then -- Medium Slow
  1217. return math.floor(lvl^3 * 6 / 5) - (lvl^2 * 15) + (lvl * 100) - 140
  1218. elseif rate == 4 then -- Slow
  1219. return math.floor(lvl^3 * 5 / 4)
  1220. elseif rate == 5 then -- Fluctuating
  1221. if lvl <= 15 then
  1222. return math.floor(lvl^3 * (math.floor((lvl+1)/3)+24)/50)
  1223. elseif lvl <= 36 then
  1224. return math.floor(lvl^3 * (lvl+14)/50)
  1225. end
  1226. return math.floor(lvl^3 * (math.floor(lvl/2)+32)/50)
  1227. end
  1228. end
  1229.  
  1230. function Pokemon:getLevelFromExperience(xp)
  1231. xp = xp or self.experience
  1232. if xp == 0 then
  1233. return 1
  1234. elseif xp >= self:getRequiredExperienceForLevel(100) then
  1235. return 100
  1236. end
  1237. local guess = 50
  1238. local inc = 50
  1239. while true do
  1240. local rxp = self:getRequiredExperienceForLevel(guess)
  1241. local rxppo = self:getRequiredExperienceForLevel(guess+1)
  1242. if rxp == xp or (rxp < xp and rxppo > xp) then
  1243. return guess
  1244. elseif rxp > xp then
  1245. inc = math.ceil(inc/2)
  1246. guess = guess - inc
  1247. elseif rxp < xp then
  1248. inc = math.ceil(inc/2)
  1249. guess = guess + inc
  1250. end
  1251. end
  1252. end
  1253.  
  1254. do -- todo
  1255. local floor = math.floor
  1256. function Pokemon:hash()
  1257. local b = 100
  1258. if self.shiny then b = b + 4 end
  1259. if self.hiddenAbility then b = b + 8 end
  1260. local ivs = self.ivs
  1261. local p = self.personality
  1262. p = {p%256,floor(p/256)%256,floor(p/65536)%256,floor(p/16777216)%256}
  1263. for i, v in pairs(p) do if v == 0 then p[i] = 33 end end
  1264. local o = self.ot or self.PlayerData.userId
  1265. o = {o%256,floor(o/256)%256,floor(o/65536)%256,floor(o/16777216)%256}
  1266. for i, v in pairs(o) do if v == 0 then o[i] = 87 end end
  1267. local n = 20+self.data.num -- CANNOT USE THIS; MUST USE BASE_EVOLUTION'S NUM
  1268. n = {n%256,floor(n/256)%256}
  1269. for i, v in pairs(n) do if v == 0 then n[i] = 87 end end
  1270. return string.char(b,o[2],n[2],p[3],p[1],12+ivs[3],112+ivs[1],106+ivs[5],n[1],p[2],28+ivs[2],113+ivs[6],o[1],68+ivs[4],p[4],o[4],44+(self.pokeball or 1),43+self.nature,o[3])
  1271. end
  1272. end
  1273.  
  1274. function Pokemon:serialize(inPC)
  1275. local buffer = BitBuffer.Create()
  1276. local version = 4
  1277. buffer:WriteUnsigned(6, version)
  1278. buffer:WriteBool(inPC and true or false)
  1279. buffer:WriteUnsigned(10, self.data.num)
  1280. buffer:WriteBool(self.egg and true or false)
  1281. if self.egg then
  1282. buffer:WriteBool(self.fossilEgg and true or false) -- v3
  1283. buffer:WriteUnsigned(7, math.max(0, math.min(127, self.eggCycles))) -- v3: 7-bit (was 6)
  1284. end
  1285. buffer:WriteBool(self.shiny and true or false)
  1286. buffer:WriteBool(self.untradable and true or false) -- v2
  1287. buffer:WriteBool(self.hiddenAbility and true or false)
  1288. buffer:WriteBool(self.swappedAbility and true or false)
  1289. buffer:WriteBool(self.nickname ~= nil)
  1290. if self.nickname then
  1291. buffer:WriteString(self.nickname)
  1292. end
  1293. buffer:WriteBool(self.forme ~= nil)
  1294. if self.forme then
  1295. buffer:WriteString(self.forme)
  1296. end
  1297. buffer:WriteUnsigned(5, self.pokeball or 1)
  1298. buffer:WriteUnsigned(21, self.experience or self:getRequiredExperienceForLevel(self.level or 1))
  1299. buffer:WriteUnsigned(32, self.personality or math.floor(2^32 * math.random()))
  1300. buffer:WriteUnsigned(5, self.nature or math.random(25))
  1301. buffer:WriteUnsigned(8, math.max(0, math.min(255, self.happiness or 0)))
  1302. buffer:WriteBool(self.happinessOT ~= nil) -- begin v1``
  1303. if self.happinessOT then
  1304. buffer:WriteUnsigned(8, self.happinessOT)
  1305. end -- end v1
  1306. local ivs = self.ivs or {}
  1307. local evs = self.evs or {}
  1308. for i = 1, 6 do
  1309. buffer:WriteUnsigned(5, ivs[i] or math.random(0, 31))
  1310. buffer:WriteUnsigned(8, math.max(0, math.min(252, evs[i] or 0)))
  1311. end
  1312. if not inPC then
  1313. buffer:WriteUnsigned(10, math.max(0, self.hp or self.maxhp))
  1314. local status = 0
  1315. if self.status then
  1316. local statuses = {brn=1, frz=2, par=3, psn=4,tox=4, slp1=5, slp2=6, slp3=7}
  1317. status = statuses[self.status] or 0
  1318. end
  1319. buffer:WriteUnsigned(3, status)
  1320. end
  1321. local moves = self:getMoves()
  1322. for i = 1, 4 do
  1323. if not moves[i] then
  1324. buffer:WriteBool(false)
  1325. break
  1326. end
  1327. buffer:WriteBool(true)
  1328. buffer:WriteUnsigned(10, moves[i].num)
  1329. buffer:WriteUnsigned(2, moves[i].ppup or 0)
  1330. if not inPC then
  1331. buffer:WriteUnsigned(6, moves[i].pp) -- TODO: with PP Up these can get higher than 6 bits :l
  1332. end
  1333. end
  1334. buffer:WriteUnsigned(33, math.max(0, self.ot or self.PlayerData.userId))
  1335. local item = self:getHeldItem()
  1336. if item and item.num then
  1337. buffer:WriteBool(true)
  1338. buffer:WriteUnsigned(10, item.num)
  1339. else
  1340. buffer:WriteBool(false)
  1341. end
  1342. local hasMarking = false
  1343. if self.marking then
  1344. for i = 1, 5 do
  1345. if self.marking[i] then
  1346. hasMarking = true
  1347. break
  1348. end
  1349. end
  1350. end
  1351. buffer:WriteBool(hasMarking)
  1352. if hasMarking then
  1353. for i = 1, 5 do
  1354. buffer:WriteBool(self.marking[i] and true or false)
  1355. end
  1356. end
  1357. local stamps = self.stamps-- v4
  1358. if stamps then
  1359. buffer:WriteUnsigned(2, #stamps)
  1360. for _, stamp in pairs(stamps) do
  1361. buffer:WriteUnsigned(4, stamp.sheet)
  1362. buffer:WriteUnsigned(5, stamp.n)
  1363. buffer:WriteUnsigned(5, stamp.color)
  1364. buffer:WriteUnsigned(3, stamp.style)
  1365. end
  1366. else
  1367. buffer:WriteUnsigned(2, 0)
  1368. end
  1369.  
  1370. return buffer:ToBase64()
  1371. end
  1372.  
  1373. function Pokemon:deserialize(str, PlayerData)
  1374. local self = {}
  1375. local buffer = BitBuffer.Create()
  1376. buffer:FromBase64(str)
  1377. local version = buffer:ReadUnsigned(6)
  1378. local inPC = buffer:ReadBool()
  1379. self.num = buffer:ReadUnsigned(10)
  1380. if buffer:ReadBool() then
  1381. self.egg = true
  1382. if version >= 3 and buffer:ReadBool() then
  1383. self.fossilEgg = true
  1384. end
  1385. self.eggCycles = buffer:ReadUnsigned(version >= 3 and 7 or 6)
  1386. end
  1387. self.shiny = buffer:ReadBool()
  1388. if version >= 2 then
  1389. local untradable = buffer:ReadBool()
  1390. if untradable then
  1391. local num = self.num
  1392. if num == 133 or num == 134 or num == 135 or num == 136 or num == 196 or num == 197 or num == 470 or num == 471 or num == 700 then
  1393. -- here we remove Eevee's untradability as a side effect of the free release
  1394. else
  1395. self.untradable = true
  1396. end
  1397. end
  1398. end
  1399. self.hiddenAbility = buffer:ReadBool()
  1400. self.swappedAbility = buffer:ReadBool()
  1401. if buffer:ReadBool() then
  1402. local nickname = buffer:ReadString()
  1403. self.nickname = nickname
  1404. spawn(function()
  1405. nickname = Pokemon:filterNickname(nickname, PlayerData.player)
  1406. self.nickname = (nickname ~= '') and nickname or nil
  1407. end)
  1408. end
  1409. if buffer:ReadBool() then
  1410. self.forme = buffer:ReadString()
  1411. end
  1412. self.pokeball = buffer:ReadUnsigned(5)
  1413. self.experience = buffer:ReadUnsigned(21)
  1414. self.personality = buffer:ReadUnsigned(32)
  1415. self.nature = buffer:ReadUnsigned(5)
  1416. self.happiness = buffer:ReadUnsigned(8)
  1417. if version >= 1 then -- Happiness resets to baseHappiness when traded;
  1418. if buffer:ReadBool() then -- If traded back to the OT, happiness is restored to the value it had before being traded away
  1419. self.happinessOT = buffer:ReadUnsigned(8) -- ^^^ uh, this was never implemented...
  1420. end
  1421. end
  1422. self.ivs = {}
  1423. self.evs = {}
  1424. for i = 1, 6 do
  1425. self.ivs[i] = buffer:ReadUnsigned(5)
  1426. self.evs[i] = buffer:ReadUnsigned(8)
  1427. end
  1428. if not inPC then
  1429. self.hp = buffer:ReadUnsigned(10)
  1430. local status = buffer:ReadUnsigned(3)
  1431. if status ~= 0 then
  1432. local statuses = {'brn', 'frz', 'par', 'psn', 'slp1', 'slp2', 'slp3'}
  1433. self.status = statuses[status]
  1434. end
  1435. end
  1436. local moves = {}
  1437. for i = 1, 4 do
  1438. if not buffer:ReadBool() then break end
  1439. moves[i] = {}
  1440. local mnum = buffer:ReadUnsigned(10)
  1441. moves[i].id = getMoveData(mnum).id
  1442. moves[i].ppup = buffer:ReadUnsigned(2)
  1443. if not inPC then
  1444. moves[i].pp = buffer:ReadUnsigned(6)
  1445. end
  1446. end
  1447. self.moves = moves
  1448. self.ot = buffer:ReadUnsigned(33)
  1449. if self.ot == 0 and PlayerData.userId > 0 then
  1450. -- 1. why does this condition exist?
  1451. -- 2. why was it occuring regularly?
  1452. -- I fixed its bug but should it even happen to begin with???
  1453. _f.Network:postToDiscord('ServerPokemon', 'Attempt to deserialize "'..str..'" ('..PlayerData.player.Name..', '..PlayerData.userId..')')
  1454. self.ot = PlayerData.userId
  1455. end
  1456. if buffer:ReadBool() then
  1457. local num = buffer:ReadUnsigned(10)
  1458. if num ~= 0 then
  1459. self.item = num
  1460. end
  1461. end
  1462. if buffer:ReadBool() then
  1463. self.marking = {}
  1464. for i = 1, 5 do
  1465. if buffer:ReadBool() then
  1466. self.marking[i] = true
  1467. end
  1468. end
  1469. end
  1470. if version >= 4 then
  1471. local stamps = {}
  1472. for i = 1, buffer:ReadUnsigned(2) do
  1473. stamps[i] = {
  1474. sheet = buffer:ReadUnsigned(4),
  1475. n = buffer:ReadUnsigned(5),
  1476. color = buffer:ReadUnsigned(5),
  1477. style = buffer:ReadUnsigned(3)
  1478. }
  1479. end
  1480. if #stamps > 0 then
  1481. self.stamps = stamps
  1482. end
  1483. end
  1484.  
  1485. return Pokemon:new(self, PlayerData)--, buffer:GetPtr()
  1486. end
  1487.  
  1488. function Pokemon:destroy()
  1489. self.PlayerData = nil -- remove circular reference
  1490. end
  1491.  
  1492.  
  1493. return Pokemon
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement