2016-11-29 14:23:00 +08:00
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="0Main" script:language="StarBasic">' 0Main: The main module for the Pokémon Go IV calculator
' by imacat <imacat@mail.imacat.idv.tw>, 2016-11-27
2016-11-28 00:18:16 +08:00
Option Explicit
2016-11-29 14:23:00 +08:00
' The stats of a Pokémon.
2016-11-28 00:18:16 +08:00
Type aStats
sNo As String
sPokemon As String
fLevel As Double
nStamina As Integer
nAttack As Integer
nDefense As Integer
nTotal As Integer
sEvolveInto As String
nEvolvedCP As Integer
nMaxCP As Integer
End Type
2016-11-29 14:23:00 +08:00
' The amount of star dust to power-up.
2016-11-28 00:18:16 +08:00
Type aStarDust
fLevel As Double
nStarDust As Integer
End Type
2016-11-29 14:23:00 +08:00
' The parameters to find the individual values.
2016-11-28 00:18:16 +08:00
Type aFindIVParam
sPokemon As String
nCP As Integer
nHP As Integer
nStarDust As Integer
nPlayerLevel As Integer
bIsNew As Boolean
nAppraisal1 As Integer
sBest As String
nAppraisal2 As Integer
2016-11-29 10:41:36 +08:00
bIsCancelled As Boolean
2016-11-28 00:18:16 +08:00
End Type
2016-11-28 23:00:20 +08:00
Private maBaseStats () As New aStats
Private mCPM () As Double, mStarDust () As Integer
2016-11-28 00:18:16 +08:00
2016-11-29 14:23:00 +08:00
' subMain: The main program
2016-11-28 00:18:16 +08:00
Sub subMain
Dim maIVs As Variant, nI As Integer, sOutput As String
Dim aQuery As New aFindIVParam, aBaseStats As New aStats
aQuery = fnAskParam
2016-11-29 10:41:36 +08:00
If aQuery.bIsCancelled Then
Exit Sub
End If
2016-11-28 00:18:16 +08:00
maIVs = fnFindIV (aQuery)
2016-11-29 14:23:00 +08:00
sOutput = ""
2016-11-28 00:18:16 +08:00
For nI = 0 To UBound (maIVs)
sOutput = sOutput _
2016-11-29 14:23:00 +08:00
& " Lv=" & maIVs (nI).fLevel _
& " Atk=" & maIVs (nI).nAttack _
& " Def=" & maIVs (nI).nDefense _
& " Sta=" & maIVs (nI).nStamina _
& " IV=" & fnFloor (maIVs (nI).nTotal * 100 / 45) & "%"
If aQuery.sPokemon <> maIVs (nI).sEvolveInto Then
2016-11-28 00:18:16 +08:00
aBaseStats = fnGetBaseStats (maIVs (nI).sEvolveInto)
2016-11-29 14:23:00 +08:00
sOutput = sOutput & " Ev=" & maIVs (nI).sEvolveInto _
& " " & maIVs (nI).nEvolvedCP
2016-11-28 00:18:16 +08:00
End If
2016-11-29 14:23:00 +08:00
If aQuery.nPlayerLevel <> 0 Then
sOutput = sOutput & " XCP=" & maIVs (nI).nMaxCP
2016-11-28 00:18:16 +08:00
End If
2016-11-29 14:23:00 +08:00
sOutput = sOutput & Chr (10)
2016-11-28 00:18:16 +08:00
Next nI
2016-11-29 14:23:00 +08:00
If sOutput = "" Then
MsgBox "Found no matching IV."
2016-11-28 00:18:16 +08:00
Else
subSaveIV (aQuery, maIVs)
End If
End Sub
2016-11-29 14:23:00 +08:00
' fnFindIV: Finds the possible individual values of the Pokémon
2016-11-28 00:18:16 +08:00
Function fnFindIV (aQuery As aFindIVParam) As Variant
Dim aBaseStats As New aStats, maIV () As New aStats
Dim fLevel As Double, nStamina As Integer
Dim nAttack As Integer, nDefense As integer
Dim nI As Integer, nJ As Integer
2016-11-28 23:00:20 +08:00
Dim fStep As Double, nCount As Integer
2016-11-28 00:18:16 +08:00
Dim aEvBaseStats As new aStats, aTempIV As New aStats
2016-11-29 14:23:00 +08:00
If aQuery.sPokemon = "" Then
2016-11-28 00:18:16 +08:00
fnFindIV = maIV
Exit Function
End If
If aQuery.bIsNew Then
2016-11-28 23:00:20 +08:00
fStep = 1
2016-11-28 00:18:16 +08:00
Else
2016-11-28 23:00:20 +08:00
fStep = 0.5
2016-11-28 00:18:16 +08:00
End If
aBaseStats = fnGetBaseStats (aQuery.sPokemon)
aEvBaseStats = fnGetBaseStats (aBaseStats.sEvolveInto)
subReadStarDust
nCount = -1
2016-11-28 23:00:20 +08:00
For fLevel = 1 To UBound (mStarDust) Step fStep
If mStarDust (CInt (fLevel - 0.5)) = aQuery.nStarDust Then
2016-11-29 14:23:00 +08:00
'For nI = 0 To UBound (maStarDust) Step nStep
' fLevel = maStarDust (nI).fLevel
' If maStarDust (nI).nStarDust = aQuery.nStarDust Then
2016-11-28 00:18:16 +08:00
For nStamina = 0 To 15
If fnCalcHP (aBaseStats, fLevel, nStamina) = aQuery.nHP Then
For nAttack = 0 To 15
For nDefense = 0 To 15
If fnCalcCP (aBaseStats, fLevel, nAttack, nDefense, nStamina) = aQuery.nCP _
And Not (fnFilterAppraisals (aQuery, nAttack, nDefense, nStamina)) Then
2016-11-28 23:00:20 +08:00
nCount = nCount + 1
2016-11-28 00:18:16 +08:00
ReDim Preserve maIV (nCount) As New aStats
2016-11-28 23:00:20 +08:00
With maIV (nCount)
2016-11-28 00:24:27 +08:00
.sNo = aBaseStats.sNo
2016-11-28 00:18:16 +08:00
.sPokemon = aQuery.sPokemon
.fLevel = fLevel
.nAttack = nAttack
.nDefense = nDefense
.nStamina = nStamina
.nTotal = nAttack + nDefense + nStamina
.sEvolveInto = aBaseStats.sEvolveInto
.nEvolvedCP = fnCalcCP (aEvBaseStats, fLevel, nAttack, nDefense, nStamina)
End With
2016-11-29 14:23:00 +08:00
If aQuery.nPlayerLevel <> 0 Then
2016-11-28 00:18:16 +08:00
maIV (nCount).nMaxCP = fnCalcCP (aEvBaseStats, aQuery.nPlayerLevel + 1.5, nAttack, nDefense, nStamina)
Else
maIV (nCount).nMaxCP = -1
End If
End If
Next nDefense
Next nAttack
End If
Next nStamina
End If
2016-11-28 23:00:20 +08:00
Next fLevel
2016-11-29 14:23:00 +08:00
' Sorts the IVs
2016-11-28 00:18:16 +08:00
For nI = 0 To UBound (maIV) - 1
For nJ = nI + 1 To UBound (maIV)
2016-11-29 14:23:00 +08:00
If fnCompareIV (maIV (nI), maIV (nJ)) > 0 Then
2016-11-28 00:18:16 +08:00
subCopyIV (maIV (nI), aTempIV)
subCopyIV (maIV (nJ), maIV (nI))
subCopyIV (aTempIV, maIV (nJ))
End If
Next nJ
Next nI
fnFindIV = maIV
End Function
2016-11-29 14:23:00 +08:00
' fnCompareIV: Compare two IVs for sorting
2016-11-28 00:18:16 +08:00
Function fnCompareIV (aIVa As aStats, aIVb As aStats) As Double
fnCompareIV = aIVb.nMaxCP - aIVa.nMaxCP
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.nEvolvedCP - aIVa.nEvolvedCP
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.nTotal - aIVa.nTotal
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.fLevel - aIVa.fLevel
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.nStamina - aIVa.nStamina
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.nAttack - aIVa.nAttack
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
fnCompareIV = aIVb.nDefense - aIVa.nDefense
2016-11-29 14:23:00 +08:00
If fnCompareIV <> 0 Then
2016-11-28 00:18:16 +08:00
Exit Function
End If
End Function
2016-11-29 14:23:00 +08:00
' subCopyIV: Copies one IV to another
2016-11-28 00:18:16 +08:00
Function subCopyIV (aFrom As aStats, aTo As aStats) As Double
With aTo
2016-11-28 00:24:27 +08:00
.sNo = aFrom.sNo
2016-11-28 00:18:16 +08:00
.sPokemon = aFrom.sPokemon
.fLevel = aFrom.fLevel
.nAttack = aFrom.nAttack
.nDefense = aFrom.nDefense
.nStamina = aFrom.nStamina
.nTotal = aFrom.nTotal
.sEvolveInto = aFrom.sEvolveInto
.nEvolvedCP = aFrom.nEvolvedCP
2016-11-28 00:24:27 +08:00
.nMaxCP = aFrom.nMaxCP
2016-11-28 00:18:16 +08:00
End With
End Function
2016-11-29 14:23:00 +08:00
' subSaveIV: Saves the found IV
2016-11-28 00:24:27 +08:00
Sub subSaveIV (aQuery As aFindIVParam, maIVs () As aStats)
Dim oDoc As Object, oSheet As Object, oRange As Object
Dim nI As Integer, oColumns As Object
Dim mData (Ubound (maIVs) + 1) As Variant
Dim mProps () As New com.sun.star.beans.PropertyValue
oDoc = StarDesktop.loadComponentFromURL ( _
2016-11-29 14:23:00 +08:00
"private:factory/scalc", "_default", 0, mProps)
2016-11-28 00:24:27 +08:00
oSheet = oDoc.getSheets.getByIndex (0)
mData (0) = Array ( _
2016-11-29 14:23:00 +08:00
"No", "Pokemon", "CP", "HP", _
"Lv", "Atk", "Def", "Sta", "IV", _
"Evolve Into", "Evolved CP", "Max CP")
2016-11-28 00:24:27 +08:00
mData (1) = Array ( _
maIVs (0).sNo, aQuery.sPokemon, aQuery.nCP, aQuery.nHP, _
maIVs (0).fLevel, maIVs (0).nAttack, maIVs (0).nDefense, _
maIVs (0).nStamina, maIVs (0).nTotal / 45, _
maIVs (0).sEvolveInto, maIVs (0).nEvolvedCP, _
maIVs (0).nMaxCP)
For nI = 1 To UBound (maIVs)
mData (nI + 1) = Array ( _
2016-11-29 14:23:00 +08:00
"", "", "", "", _
2016-11-28 00:24:27 +08:00
maIVs (nI).fLevel, maIVs (nI).nAttack, maIVs (nI).nDefense, _
maIVs (nI).nStamina, maIVs (nI).nTotal / 45, _
maIVs (nI).sEvolveInto, maIVs (nI).nEvolvedCP, _
maIVs (nI).nMaxCP)
Next nI
oRange = oSheet.getCellRangeByPosition ( _
0, 0, UBound (mData (0)), UBound (mData))
oRange.setDataArray (mData)
2016-11-29 14:23:00 +08:00
oRange.setPropertyValue ("VertJustify", _
2016-11-28 00:24:27 +08:00
com.sun.star.table.CellVertJustify.TOP)
oRange = oSheet.getCellRangeByPosition ( _
0, 1, 0, UBound (mData))
oRange.merge (True)
oRange = oSheet.getCellRangeByPosition ( _
1, 1, 1, UBound (mData))
oRange.merge (True)
oRange = oSheet.getCellRangeByPosition ( _
2, 1, 2, UBound (mData))
oRange.merge (True)
oRange = oSheet.getCellRangeByPosition ( _
3, 1, 3, UBound (mData))
oRange.merge (True)
oRange = oSheet.getCellRangeByPosition ( _
8, 1, 8, UBound (mData))
2016-11-29 14:23:00 +08:00
oRange.setPropertyValue ("NumberFormat", 10)
2016-11-28 00:24:27 +08:00
oColumns = oSheet.getColumns
For nI = 0 To UBound (mData (0))
oColumns.getByIndex (nI).setPropertyValue ( _
2016-11-29 14:23:00 +08:00
"OptimalWidth", True)
2016-11-28 00:24:27 +08:00
Next nI
End Sub
2016-11-29 14:23:00 +08:00
' fnFilterAppraisals: Filters the IV by the appraisals.
2016-11-28 00:18:16 +08:00
Function fnFilterAppraisals (aQuery As aFindIVParam, nAttack As Integer, nDefense As Integer, nStamina As Integer) As Boolean
Dim nTotal As Integer, nMax As Integer, sBest As String
2016-11-29 14:23:00 +08:00
' The first appraisal.
2016-11-28 00:18:16 +08:00
nTotal = nAttack + nDefense + nStamina
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal1 = 1 And Not (nTotal >= 37) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal1 = 2 And Not (nTotal >= 30 And nTotal <= 36) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal1 = 3 And Not (nTotal >= 23 And nTotal <= 29) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal1 = 4 And Not (nTotal <= 22) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
' The best stats.
2016-11-28 00:18:16 +08:00
nMax = nAttack
2016-11-29 14:23:00 +08:00
If nDefense > nMax Then
2016-11-28 00:18:16 +08:00
nMax = nDefense
End If
2016-11-29 14:23:00 +08:00
If nStamina > nMax Then
2016-11-28 00:18:16 +08:00
nMax = nStamina
End If
2016-11-29 14:23:00 +08:00
If aQuery.sBest <> "" Then
sBest = ""
2016-11-28 00:18:16 +08:00
If nAttack = nMax Then
2016-11-29 14:23:00 +08:00
sBest = sBest & "Atk "
2016-11-28 00:18:16 +08:00
End If
If nDefense = nMax Then
2016-11-29 14:23:00 +08:00
sBest = sBest & "Def "
2016-11-28 00:18:16 +08:00
End If
If nStamina = nMax Then
2016-11-29 14:23:00 +08:00
sBest = sBest & "Sta "
2016-11-28 00:18:16 +08:00
End If
2016-11-29 14:23:00 +08:00
If aQuery.sBest <> sBest Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
End If
2016-11-29 14:23:00 +08:00
' The second appraisal.
2016-11-28 00:18:16 +08:00
If aQuery.nAppraisal2 = 1 And Not (nMax = 15) Then
fnFilterAppraisals = True
Exit Function
End If
If aQuery.nAppraisal2 = 2 And Not (nMax = 13 Or nMax = 14) Then
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal2 = 3 And Not (nMax >= 8 And nMax <= 12) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
2016-11-29 14:23:00 +08:00
If aQuery.nAppraisal2 = 4 And Not (nMax <= 7) Then
2016-11-28 00:18:16 +08:00
fnFilterAppraisals = True
Exit Function
End If
fnFilterAppraisals = False
End Function
2016-11-29 14:23:00 +08:00
' fnCalcCP: Calculates the combat power of the Pokémon
2016-11-28 00:18:16 +08:00
Function fnCalcCP (aBaseStats As aStats, fLevel As Double, nAttack As Integer, nDefense As Integer, nStamina As Integer) As Integer
fnCalcCP = fnFloor ((aBaseStats.nAttack + nAttack) _
* ((aBaseStats.nDefense + nDefense) ^ 0.5) _
* ((aBaseStats.nStamina + nStamina) ^ 0.5) _
* (fnGetCPM (fLevel) ^ 2) / 10)
End Function
2016-11-29 14:23:00 +08:00
' fnCalcHP: Calculates the hit points of the Pokémon
2016-11-28 00:18:16 +08:00
Function fnCalcHP (aBaseStats As aStats, fLevel As Double, nStamina As Integer) As Integer
fnCalcHP = fnFloor ((aBaseStats.nStamina + nStamina) _
* fnGetCPM (fLevel))
End Function
2016-11-29 14:23:00 +08:00
' fnGetBaseStats: Returns the base stats of the Pokémon.
2016-11-28 00:18:16 +08:00
Function fnGetBaseStats (sPokemon As String) As aStats
Dim nI As Integer
subReadBaseStats
For nI = 0 To UBound (maBaseStats)
If maBaseStats (nI).sPokemon = sPokemon Then
fnGetBaseStats = maBaseStats (nI)
Exit Function
End If
Next nI
2016-11-28 23:00:20 +08:00
End Function
2016-11-28 00:18:16 +08:00
2016-11-29 14:23:00 +08:00
' fnGetCPM: Returns the combat power multiplier.
2016-11-28 00:18:16 +08:00
Function fnGetCPM (fLevel As Double) As Double
Dim nI As Integer
subReadCPM
2016-11-28 23:00:20 +08:00
If CInt (fLevel) = fLevel Then
fnGetCPM = mCPM (fLevel)
Else
fnGetCPM = ((mCpm (fLevel - 0.5) ^ 2 _
+ mCpm (fLevel + 0.5) ^ 2) / 2) ^ 0.5
End If
End Function
2016-11-28 00:18:16 +08:00
2016-11-29 14:23:00 +08:00
' fnFloor: Returns the floor of the number
2016-11-28 00:18:16 +08:00
Function fnFloor (fNumber As Double) As Integer
fnFloor = CInt (fNumber - 0.5)
End Function
2016-11-29 14:23:00 +08:00
' subReadBaseStats: Reads the base stats table.
2016-11-28 00:18:16 +08:00
Sub subReadBaseStats
2016-11-28 23:00:20 +08:00
Dim mData As Variant, nI As Integer
2016-11-28 00:18:16 +08:00
If UBound (maBaseStats) = -1 Then
2016-11-28 23:00:20 +08:00
mData = fnGetBaseStatsData
ReDim Preserve maBaseStats (UBound (mData)) As New aStats
For nI = 0 To UBound (mData)
With maBaseStats (nI)
.sNo = mData (nI) (1)
.sPokemon = mData (nI) (0)
.nStamina = mData (nI) (2)
.nAttack = mData (nI) (3)
.nDefense = mData (nI) (4)
.sEvolveInto = mData (nI) (5)
2016-11-28 00:18:16 +08:00
End With
2016-11-28 23:00:20 +08:00
Next nI
2016-11-28 00:18:16 +08:00
End If
2016-11-28 23:00:20 +08:00
End Sub
2016-11-28 00:18:16 +08:00
2016-11-29 14:23:00 +08:00
' subReadCPM: Reads the CPM table.
2016-11-28 00:18:16 +08:00
Sub subReadCPM
2016-11-28 23:00:20 +08:00
If UBound (mCPM) = -1 Then
mCPM = fnGetCPMData
2016-11-28 00:18:16 +08:00
End If
2016-11-28 23:00:20 +08:00
End Sub
2016-11-28 00:18:16 +08:00
2016-11-29 14:23:00 +08:00
' subReadStarDust: Reads the star dust table.
2016-11-28 00:18:16 +08:00
Sub subReadStarDust
2016-11-28 23:00:20 +08:00
If UBound (mStarDust) = -1 Then
mStarDust = fnGetStarDustData
2016-11-28 00:18:16 +08:00
End If
2016-11-28 23:00:20 +08:00
End Sub
2016-11-29 14:23:00 +08:00
</script:module>