stevenssec / pokemonbattlelib Goto Github PK
View Code? Open in Web Editor NEWA portable library for accurately simulating Pokemon battles.
License: GNU General Public License v3.0
A portable library for accurately simulating Pokemon battles.
License: GNU General Public License v3.0
Is your feature request related to a problem? Please describe.
Users are going to want to build parties quickly, and we're going to want it to write tests.
Currently, the steps to building a party are:
This kinda sucks, especially because of step 5.
Describe the solution you'd like
There should be some way to generate pokemon with correct stats based on the national dex number and level
The process should look more like:
However, it needs to still be possible to hand craft pokemon if needed. This would be just a convenience tool.
Describe alternatives you've considered
Additional context
Add functionality for held items that affect stats. There is a lot of custom functionality here, including changing priorities, restricting moves, changing immunities, and boosting type damage.
Blocked by #8.
Obviously, we need a type to represent a Pokemon in a battle. Keep memory footprint in mind when considering what types to use. Feel free to add any enums that you need to accomplish this.
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#pokemon
It's not necessary for the first iteration of this type to be perfect. We can change it later if needed.
type Pokemon struct
that are necessary to have in a Pokemon battle, or to be able to obtain external metadata.
Stringer
interface for Pokemon
. Example: https://tour.golang.org/methods/17Add transactions/helper functions to apply 1 or more status effects to a Pokemon.
We need a way to track the current state of a Pokemon battle.
It's not necessary for the first iteration of this type to be perfect. We can change it later if needed.
type Battle struct
that necessary for a Pokemon battle.Add transactions/helper functions to change friendship in Pokemon.
Add transactions/helper functions to cure one or more status effects from a Pokemon.
We need test cases to ensure the accuracy of our Pokemon battle implementation.
Eventually, we will turn these into automated test cases.
docs/example-battles.md
)
Is your feature request related to a problem? Please describe.
We need some way to supply the battle with turns from an Agent in a specific order in tests.
Describe the solution you'd like
An Agent
that has a channel that it takes a Turn
from and returns it when Act
is called. This will allow us to write tests that check specific sequences of Turns
easier.
Describe alternatives you've considered
Additional context
Sort turns based on move priority and add tests that specifically check for priority between turns and properly sorts them.
In a Pokemon battle, certain types of turns are supposed to occur before others.
Relevant code:
Lines 118 to 122 in 07c4cf0
Sort turnOrder
in descending order by Priority()
on the corresponding turns. Allow the ability to add other factors that can affect the sorting order.
This may be useful: https://golang.org/pkg/sort/
Currently, the code generation script parses the available moves, but it does not actually output any generated code for them.
Add functionality for effects of berries in battle. Each berry is consumed upon usage and typically affects 1 or more stat values.
See: https://veekun.com/dex/items/berries
Num | Item | Effect |
---|---|---|
57 | Apicot Berry | Held: Consumed at 1/4 max HP to boost Special Defense. |
62 | Custap Berry | Held: Consumed at 1/4 max HP when using a move to go first. |
54 | Ganlon Berry | Held: Consumed at 1/4 max HP to boost Defense. |
58 | Lansat Berry | Held: Consumed at 1/4 max HP to boost critical hit ratio by two stages. |
53 | Liechi Berry | Held: Consumed at 1/4 max HP to boost Attack. |
61 | Micle Berry | Held: Consumed at 1/4 max HP to boost accuracy of next move by 20%. (Gen IV: Perfect accuracy) |
56 | Petaya Berry | Held: Consumed at 1/4 max HP to boost Special Attack. |
55 | Salac Berry | Held: Consumed at 1/4 max HP to boost Speed. |
59 | Starf Berry | Held: Consumed at 1/4 max HP to boost a random stat by two stages. |
Num | Item | Effect |
---|---|---|
5 | Aspear Berry | Held: Consumed when frozen to cure frozen. |
1 | Cheri Berry | Held: Consumed when paralyzed to cure paralysis. |
2 | Chesto Berry | Held: Consumed when asleep to cure sleep. |
6 | Leppa Berry | Held: Consumed when a move runs out of PP to restore its PP by 10. |
9 | Lum Berry | Held: Consumed to cure any status condition or confusion. |
7 | Oran Berry | Held: Consumed at 1/2 max HP to recover 10 HP. |
3 | Pecha Berry | Held: Consumed when poisoned to cure poison. |
8 | Persim Berry | Held: Consumed when confused to cure confusion. |
4 | Rawst Berry | Held: Consumed when burned to cure a burn. |
10 | Sitrus Berry | Held: Consumed at 1/2 max HP to recover 1/4 max HP. |
Num | Item | Effect |
---|---|---|
60 | Enigma Berry | Held: Consumed when struck by a super-effective attack to restore 1/4 max HP. |
63 | Jaboca Berry | Held: Consumed to deal 1/8 attacker's max HP when holder is struck by a physical attack. |
? | Kee Berry | Held: When the holder is hit by a physical move, increases its Defense by one stage. |
? | Maranga Berry | Held: When the holder is hit by a special move, increases its Special Defense by one stage. |
64 | Rowap Berry | Held: Consumed to deal 1/8 attacker's max HP when holder is struck by a special attack. |
Num | Item | Effect |
---|---|---|
14 | Aguav Berry | Held: Consumed at 1/2 max HP to restore 1/8 max HP. Confuses Pokémon that dislike bitter flavor. |
11 | Figy Berry | Held: Consumed at 1/2 max HP to restore 1/8 max HP. Confuses Pokémon that dislike spicy flavor. |
15 | Iapapa Berry | Held: Consumed at 1/2 max HP to restore 1/8 max HP. Confuses Pokémon that dislike sour flavor. |
13 | Mago Berry | Held: Consumed at 1/2 max HP to restore 1/8 max HP. Confuses Pokémon that dislike sweet flavor. |
12 | Wiki Berry | Held: Consumed at 1/2 max HP to restore 1/8 max HP. Confuses Pokémon that dislike dry flavor. |
Num | Item | Effect |
---|---|---|
51 | Babiri Berry | Held: Consumed when struck by a super-effective Steel-type attack to halve the damage. |
47 | Charti Berry | Held: Consumed when struck by a super-effective Rock-type attack to halve the damage. |
52 | Chilan Berry | Held: Consumed when struck by a Normal-type attack to halve the damage. |
41 | Chople Berry | Held: Consumed when struck by a super-effective Fighting-type attack to halve the damage. |
44 | Coba Berry | Held: Consumed when struck by a super-effective Flying-type attack to halve the damage. |
50 | Colbur Berry | Held: Consumed when struck by a super-effective Dark-type attack to halve the damage. |
49 | Haban Berry | Held: Consumed when struck by a super-effective Dragon-type attack to halve the damage. |
48 | Kasib Berry | Held: Consumed when struck by a super-effective Ghost-type attack to halve the damage. |
42 | Kebia Berry | Held: Consumed when struck by a super-effective Poison-type attack to halve the damage. |
36 | Occa Berry | Held: Consumed when struck by a super-effective Fire-type attack to halve the damage. |
37 | Passho Berry | Held: Consumed when struck by a super-effective Water-type attack to halve the damage. |
45 | Payapa Berry | Held: Consumed when struck by a super-effective Psychic-type attack to halve the damage. |
39 | Rindo Berry | Held: Consumed when struck by a super-effective Grass-type attack to halve the damage. |
43 | Shuca Berry | Held: Consumed when struck by a super-effective Ground-type attack to halve the damage. |
46 | Tanga Berry | Held: Consumed when struck by a super-effective Bug-type attack to halve the damage. |
38 | Wacan Berry | Held: Consumed when struck by a super-effective Electric-type attack to halve the damage. |
40 | Yache Berry | Held: Consumed when struck by a super-effective Ice-type attack to halve the damage. |
We need a Transaction
that can tell the battle that a pokemon has fainted.
In SimulateRound
where it says TODO: Implement fight
, make it so that the move deals damage to the target pokemon.
You can't implement all the damage modifiers right now, so just do the bare minimum.
Relevant code:
Line 127 in 07c4cf0
We currently use a mix of int
, uint
, uint8
, uint16
, and float64
throughout the library. I think the performance benefits do not outweigh the confusion from mixing these types together, so I suggest that we pick 1 integer type and one floating point type.
Add all items falling under the medicine category.
We need some way to process turns from Agent
s, without having the agents directly modify the state of the battle.
We need an interface to represent the entities that engage in a battle. The idea is to have an Agent
interface that, when implemented, allows an end user or bot to receive information about the battle and complete a turn.
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#before-the-battle
type Agent interface
that are necessary in order to accommodate the 2 use cases listed above.Currently, the code generation for pokemon only generates code to define their national dex number, and nothing else.
Now that #6 is complete, we need to add the rest of the fields to the code generation.
We need to be able to tell the user that the battle has ended. More specifically, we need a Transaction
that will end the battle.
Relevant code:
Lines 41 to 50 in 07c4cf0
This will represent a turn where a Trainer uses an item on their Pokemon (or an opposing Pokemon in the case of using a Poke Ball in a wild Pokemon battle).
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#bag-using-an-item
Items and their effect have yet to be implemented in full, so the actual use of the item does not have to have an effect yet.
Using an item always takes precedence to any FightTurn
s that may occur, essentially placing it in the highest priority bracket (higher than any move would have).
FightTurn
sSimulateRound()
We decided in a GBM that LinkAgentParty was not necessary, and just increases complexity.
We need a way keep track of single and dual type Pokemon.
It's not necessary for the first iteration of this type to be perfect. We can change it later if needed.
ElementalType
Add support for battle items which are one-time stat boosting items.
If a pokemon faints before taking it's turn, it will ignore the fact that it is dead, and take it's turn anyway.
To Reproduce
Code snippet to reproduce the problem (if applicable)
func TestBattleDeadPokemonForfeitTurn(t *testing.T) {
a1 := Agent(dumbAgent{})
a2 := Agent(dumbAgent{})
party1 := NewParty(&a1, 0)
pkmn1 := GetPokemon(4)
pkmn1.Stats = [6]uint{30, 10, 10, 10, 10, 10}
pkmn1.CurrentHP = 1
pound := GetMove(1)
pkmn1.Moves[0] = £
party1.AddPokemon(&pkmn1)
party2 := NewParty(&a2, 1)
pkmn2 := GetPokemon(7)
pkmn2.Stats = [6]uint{30, 10, 10, 10, 10, 100}
pkmn2.CurrentHP = 30
pkmn2.Moves[0] = £
party2.AddPokemon(&pkmn2)
b := NewBattle()
b.AddParty(party1, party2)
err := b.Start()
if err != nil {
t.Fatal("failed to start battle")
}
transactions, ended := b.SimulateRound()
if !ended {
t.Error("Expected SimulateRound to indicate that the battle has ended, but it did not.")
}
if n := len(transactions); n != 3 {
t.Errorf("Expected 3 transactions to occur, got %d", n)
}
logtest := []struct {
turn Transaction
want string
}{
{
turn: transactions[0],
want: "Squirtle used Pound on Charmander for 3 damage.",
},
{
turn: transactions[1],
want: "Charmander fainted.",
},
{
turn: transactions[2],
want: "The battle has ended.",
},
}
for _, tt := range logtest {
got := tt.turn.BattleLog()
if got != tt.want {
t.Errorf("Expected battle log to be %s, got %s", tt.want, got)
}
}
}
func TestBattleDeadPokemonForfeitTurn2(t *testing.T) {
a1 := Agent(dumbAgent{})
a2 := Agent(dumbAgent{})
party1 := NewParty(&a1, 0)
pkmn1 := GetPokemon(4)
pkmn3 := GetPokemon(387)
pkmn1.Stats = [6]uint{30, 10, 10, 10, 10, 10}
pkmn1.CurrentHP = 1
pkmn3.Stats = [6]uint{30, 10, 10, 10, 10, 10}
pkmn3.CurrentHP = 30
pound := GetMove(1)
pkmn1.Moves[0] = £
pkmn3.Moves[0] = £
party1.AddPokemon(&pkmn1, &pkmn3)
party2 := NewParty(&a2, 1)
pkmn2 := GetPokemon(7)
pkmn2.Stats = [6]uint{30, 10, 10, 10, 10, 100}
pkmn2.CurrentHP = 30
pkmn2.Moves[0] = £
party2.AddPokemon(&pkmn2)
b := NewBattle()
b.AddParty(party1, party2)
err := b.Start()
if err != nil {
t.Fatal("failed to start battle")
}
transactions, _ := b.SimulateRound()
if n := len(transactions); n != 3 {
t.Errorf("Expected 3 transactions to occur, got %d", n)
}
logtest := []struct {
turn Transaction
want string
}{
{
turn: transactions[0],
want: "Squirtle used Pound on Charmander for 3 damage.",
},
{
turn: transactions[1],
want: "Charmander fainted.",
},
{
turn: transactions[2],
want: "Turtwig was sent out.",
},
}
for _, tt := range logtest {
got := tt.turn.BattleLog()
if got != tt.want {
t.Errorf("Expected battle log to be %s, got %s", tt.want, got)
}
}
}
Inactive pokemon should be unable to take turns. If a pokemon is deactivated before it takes it's turn, the turn is ignored.
Additional context
When using the library as intended, it's currently impossible for agents to initialize or modify the values for FightTurn.
We need a type to represent the metadata of a Pokemon's moves at runtime. This won't be responsible for handling side effects of moves yet.
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#moves
type Move struct
that are necessary to have in a Pokemon battle, or to be able to obtain external metadata.Stringer
interface for Move
. Example: https://tour.golang.org/methods/17We need an interface to handle random number generators. More specifically, we need an interface that we can use to implement various RNG algorithms used in Pokemon games. See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#rng
For the initial seed, since getting the delay between the player starting the game and pressing "Continue", we can probably ignore it.
This will represent a turn where a Trainer changes their active Pokemon (the one currently battling) to a Pokemon in their party that has not yet fainted.
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#pokemon-switching-out
Switching Pokemon always takes precedence to any FightTurn
s that may occur, essentially placing it in the highest priority bracket (higher than any move would have). (The exception is the move Pursuit, but this has not been implemented yet. It should be kept in mind while designing the type though.)
FightTurn
sSimulateRound()
Relevant code:
Lines 53 to 57 in 07c4cf0
Held items change the way that a Pokemon battle functions drastically. Each hold item belongs to a class (such as Stat Modifier, Medicine, Berries, or other effects. Representing items will be challenging, as there are many different types of items that produce different effects. Also, we must determine if we want to include all possible items or only those which have an affect on the battle itself.
This issue should be incremental, with the data representation being the first and simplest layer.
go generate does not regenerate pokedex_GEN.go
To Reproduce
pokedex_GEN.go
go generate
pokedex_GEN.go
is not created.go generate
should regenerate pokedex_GEN.go
, even if pokedex_GEN.go
is not already present.
Additional context
Seems like pokedex.go
was removed. pokedex.go
should be recreated with
//go:generate go run data/gen.go
Note that there is no spaces in //go:generate
GetOpponents
returns the same results as GetAllies
GetAllies
should return friendly targets.
GetOpponents
should return enemy targets.
Additional context
We need to provide code examples for starting a new battle in the documentation. Preferably, we should have a minimal example in the readme, as well as an example or 2 in examples_test.go
.
For some reason, some people's editors are not automatically running gofmt
on the code. This causes erroneous changes to be made when somebody's editor does auto run gofmt
, and it clogs up diffs when reviewing pull requests.
test -z $(gofmt -l . | tr -d '\n')
returns non-zero exit code if this test failsTransactions are becoming too complex to keep in the scope of battles. We can introduce a new file, transactions.go
to manage the different types of transactions as they scale as well as test them separately without creating battle instances. Additionally, the logic performed by transactions should be separate so that we can unit test its functionality.
Quick example:
ItemTurn
should add transactions based on the item function. Using a potion should produce an ItemTransaction
(to consume the potion) and a HealTransaction
(to restore HP). The handlers for both transactions should be separate functions that we can test.
Add transactions/helper functions to change a Pokemon's stat stages in battle. See https://bulbapedia.bulbagarden.net/wiki/Stat#Stat_modifiers.
This will represent a turn where a Trainer or Pokemon attempts to leave a battle.
See: https://github.com/StevensSEC/pokemonbattlelib/wiki/Requirements#run-running-away
This option has different behavior depending on if the battle is between a player Trainer and another player Trainer, a player Trainer and an NPC Trainer, or a Trainer and a wild Pokemon:
In a battle between two player Trainers, this option is equivalent to attempt to forfeit the match. The match ends in a loss for the player Trainer who selected this option if the other Trainer selects any other option. The match ends in a draw if both Trainers select this option on the same turn.
In a battle between a player Trainer and an NPC Trainer, this option cannot be selected, and a message is displayed to warn the player Trainer without passing their turn. NPC Trainers will not select this option.
In a battle between a player Trainer and a wild Pokemon, if the player Trainer attempts to flee, the Speeds of the two Pokemon active in the battle are compared and success is determined using the formula linked above. If the wild Pokemon attempts to flee, it succeeds without needing to compare its Speed. If either Pokemon has an effect that prevents them from fleeing, selecting this option fails. This will not pass the turn for the Trainer, and the wild Pokemon cannot select this option.
Multi player Trainer case functional
Trainer and NPC case functional
Trainer and wild Pokemon case functional
Add case to SimulateRound()
Running takes precedence over FightTurn
s
Some of the current tests that check the std output are not actually checking it.
To Reproduce
If you take the TestBattleOneRound
and change the expected output, the test will still pass.
Evironment:
Additional context
We need some way for battles to generate random numbers predictably even if the user is running multiple battles at the same time.
To do this, we need to add a field to the battle struct with the type RNG
(which is already defined in rng.go
).
Lines 11 to 17 in 8969e52
NewBattle
should initialize this field.
Lines 28 to 33 in 8969e52
Is your feature request related to a problem? Please describe.
We need some way to let users know what happened in each round of the battle.
Describe the solution you'd like
Possible solution:
BattleLog()
method that outputs a string that would be end-user facing (eg. "Bulbasaur used X for -Y HP. It was super effective!"), and also have Turns make data about the result publicly accessible so that users could do animations and stuff. The battle could then just record the turns.Additional context
Also may be necessary to fix #49 .
The \data
directory contains some extra csv files. For example, conquest_kingdoms_names.csv
contains the names of the kingdoms from the Pokemon Conquest spinoff game and super_contest_effect_prose.csv
contains the effect text for moves during a Super Contest. This might make it confusing what information needs to be used in the future.
Remove csv files not directly relevant to Pokemon data, move data, or any other data that would be relevant in a Pokemon battle.
pkg.go.dev doesn't seem to be picking up our nightly releases right away.
Expected documentation on pkg.go.dev to be up to date.
Additional context
Maybe it requires a new tag every time instead of updating an existing tag.
It does update, but every 2-3 weeks?
Add transactions and helper functions to manipulate EVs of a Pokemon.
We need to be able to access metadata about pokemon, moves, etc at runtime. pokedex.go
should manage this information.
Code generation based on files. When go build
is run, it should run a script to generate the code with the metadata. This is accomplished with the magic comment go:generate
.
This example will run gen.go
before building the rest of the package.
//go:generate go run gen.go
The script should read some files out of the data/
directory, and generate code based on it's contents.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.