Transaction
D3C97F9F1B2541…5D4FB663168E
Block 556,215 · index 0 · indexed
Summary
- Hash
- D3C97F9F1B254175E363DD26C1A9920C61BDD9B6CAFDF00798FC5D4FB663168E
- Block
- 556,215
- Size
- 98332 bytes
- Gas used
- 127,266,771 / 200,000,000
- Fee
- 200000 ugnot
- Status
- success
Messages
- Attached funds
- 25000000 ugnot
Arguments · 24
- #1planes
- #2doc.gno
- #3// v0 - Unaudited: This is an initial version that has not yet been formally audited. // Use in production at your own risk. // // Package planes is a collection of 777 plane NFTs that pilots fly in // gnofly, a multiplayer plane game. It is a GRC721 token built on // gno.land/p/nt/grc721/v0 with the royalty extension. // // Every plane is drawn in a table committed with the realm (table.gno): a // name, one of the nine models the game client draws, a pilot (none or a // gnome), three colours, a tier and the colour of its laser, the shots // every pilot sees it fire. The designs stay procedural in the client; the // token stores only these traits. Id 777 is the super-gnome, a // 1/1 that is a gnome flying like a superhero rather than a plane. The table // is public; which ids a mint gets is drawn at random among the ones left, // 1 to 7 per call (draw.gno). // // Three kinds of callers write to it: // // - anyone mints the next plane with the price attached (Mint), transfers, // approves and burns their planes (TransferFrom, Approve, // SetApprovalForAll, Burn); // - the admins of the game realm open and close the mint and tune its // price, its per-wallet cap, the image URL and the royalty (SetMintOpen, // SetPrice, SetMintCap, SetImageBase, SetRoyaltyBps); // - nobody else: there is no reserve and no airdrop. // // The realm keeps no roles and no money of its own. The admins are those of // gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/game/v0, asked // at the time of each call, and every mint is forwarded to its treasury in // the same transaction. The royalty of a resale, 5% by default, names the // treasury too. // // Reads are plain functions meant for vm/qeval. The ones ending in JSON // return a single string holding a JSON document. PlanesOf and OwnerOf are // what the game server reads: ownership is the only on-chain fact of a // plane, which one a pilot flies is picked in the game's hangar and checked // against OwnerOf by the server. Render exposes the // same data as markdown for gnoweb. The read side of the token and of its // royalty extension is exported as Token and Royalties, for other realms. // No metadata is stored per token: TokenMetadata and TokenURI are computed // from the table and the image base on every read. // // Storage is paid for at deploy, so the realm is kept small: the table is one // string read in place, refusals are string constants, and the settings are // read through CollectionJSON rather than one getter each. package planes
- #4draw.gno
- #5package planes import ( "chain/runtime" "crypto/sha256" "encoding/binary" "time" ) // Planes are minted in a random order: each mint draws one of the ids not // minted yet. The id drawn is the token id and the row of the table, so // whoever draws 777 gets the SuperGnome. // // The pool of ids left is a byte string of two bytes per id, big-endian, // 1554 bytes at deploy: a slice of 777 int64 would cost several times the // storage. A draw takes the id at a random index and moves the last id into // its place (swap-remove), so every id comes out exactly once and a draw // costs the same at any point of the sale. // // The randomness is pseudo-random, from what a realm can see: the sha256 of // the block height, the block time, the minter, the count minted so far and // the hash of the previous draw. A validator could nudge the block time, a // user could try to time their block; nobody can see a draw and undo it, // because Mint only accepts direct user calls (a contract cannot call Mint, // look at the id and panic to try again). That is enough for this // collection; it is not for anything with money riding on the outcome. // pool holds the ids not minted yet, two bytes each. Its length over two is // how many are left. var pool []byte // mintedBits has one bit per id, set once the id is minted (burned or not): // what tells a burned plane from one not minted yet, without scanning pool. var mintedBits []byte // lastDraw is the hash of the previous draw, chained into the next. var lastDraw [32]byte // testDraw, when set by a test, replaces the hash to pick an index in a pool // of n ids. It is never set outside the tests. var testDraw func(n int) int // resetPool fills the pool with every id, from 777 down to 1, and seeds the // chain of draws from the realm's path. func resetPool(pkgPath string) { pool = make([]byte, 2*supply) for i := int64(0); i < supply; i++ { binary.BigEndian.PutUint16(pool[2*i:], uint16(supply-i)) } mintedBits = make([]byte, (supply+7)/8) lastDraw = sha256.Sum256([]byte(pkgPath)) } // left returns how many ids are not minted yet. func left() int64 { return int64(len(pool) / 2) } // drawHash is the hash a draw picks its index from. It is a pure function of // its inputs, so that the tests can check what moves it. func drawHash(height, nanos int64, minter address, minted int64, prev [32]byte) [32]byte { buf := make([]byte, 0, 8+8+len(minter)+8+32) buf = binary.BigEndian.AppendUint64(buf, uint64(height)) buf = binary.BigEndian.AppendUint64(buf, uint64(nanos)) buf = append(buf, minter...) buf = binary.BigEndian.AppendUint64(buf, uint64(minted)) buf = append(buf, prev[:]...) return sha256.Sum256(buf) } // drawID takes one id out of the pool, at random, for minter, and marks it // minted. The pool must not be empty. func drawID(minter address) int64 { n := len(pool) / 2 var i int if testDraw != nil { i = testDraw(n) } else { lastDraw = drawHash(runtime.ChainHeight(), time.Now().UnixNano(), minter, Minted(), lastDraw) // The first 8 bytes modulo the pool size: the bias of a modulo of // 2^64 by at most 777 is under 777/2^64, nothing. i = int(binary.BigEndian.Uint64(lastDraw[:8]) % uint64(n)) } id := int64(binary.BigEndian.Uint16(pool[2*i:])) copy(pool[2*i:2*i+2], pool[2*(n-1):2*n]) pool = pool[:2*(n-1)] mintedBits[(id-1)/8] |= 1 << uint((id-1)%8) return id } // wasMinted reports whether id was ever minted, burned since or not. func wasMinted(id int64) bool { if id < 1 || id > supply { return false } return mintedBits[(id-1)/8]&(1<<uint((id-1)%8)) != 0 }
- #6errors.gno
- #7package planes // The refusals of this realm, as strings. The game and arena realms keep // theirs as error values; this one is published with a 42 KB table and every // byte of state is paid for at deploy. Measured on a mainnet-like node, an // errors.New value costs about 1.15 KB of storage (a pointer, a heap item and // a struct, each with its header) where a string constant costs its length: // twenty of them are 2 GNOT against 0.1. A panic with a string aborts the // call with the same message. const ( errSpoofedRealm = "gnofly: spoofed realm" errNotAdmin = "gnofly: caller is not an admin" errBadTable = "gnofly: the plane table does not run from 1 to 777" errCorruptRow = "gnofly: corrupt plane row" errUnknownPlane = "gnofly: unknown plane" errNotMinted = "gnofly: plane not minted" errNotPlaneOwner = "gnofly: caller does not own this plane" errMintClosed = "gnofly: the mint is closed" errSoldOut = "gnofly: every plane is minted" errCapReached = "gnofly: this wallet minted as many planes as the cap allows" errNotUserCall = "gnofly: Mint must be called directly by a user (maketx call)" errInvalidCount = "gnofly: mint 1 to 7 planes at a time" errInvalidPrice = "gnofly: price must be between 1000000 and 10000000000 ugnot" errInvalidCap = "gnofly: cap must be between 1 and 777" errInvalidBase = "gnofly: image base must be an https URL ending in /, 12 to 200 characters of [A-Za-z0-9./_-:]" errInvalidRoyalty = "gnofly: royalty must be between 0 and 1000 basis points" )
- #8gnomod.toml
- #9module = "gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/planes" gno = "0.9"
- #10json.gno
- #11package planes import ( "strings" "gno.land/p/onbloc/json/v0" ) // The JSON documents are built with gno.land/p/onbloc/json/v0, which quotes // every string. Keys come out in the order they are written: a gno map // iterates in insertion order, and the library keeps an object's members in // one. Numbers are float64 in the library and printed without exponent or // decimal point when whole, which every number here is, far under 2^53. // PlaneJSON returns one plane as a JSON object, minted or not: // // { "id": 42, "name": "Storm Saint", "model": "delta", "pilot": "gnome", // "body": "#1e1b4b", "wing": "#1e293b", "accent": "#00f5ff", "tier": "epic", // "laser": "#39ff14", "image": "https://gnofly.xyz/nft/collections/planes/042.png", "owner": "g1..." } // // The output has no whitespace. "owner" is "" for a plane not minted, or // burned. An id outside 1 to 777 returns "". Which plane a pilot flies is // not on-chain: the game server checks the owner when a pilot picks one. func PlaneJSON(id int64) string { p, ok := getPlane(id) if !ok { return "" } b := json.Builder() writePlane(b, p) b.WriteString("image", imageURL(id)) b.WriteString("owner", ownerOf(id).String()) return encode(b.Node()) } // PlanesOf returns the ids of the planes addr owns as a JSON array, in // ascending order: [3,42,700]. It is [] for an address without planes. func PlanesOf(addr address) string { ids := []*json.Node{} if n, err := Token.BalanceOf(addr); err == nil && n > 0 { // Ids are dense, 1 to 777: a scan that stops at the last plane of // addr is cheaper than keeping a list per owner up to date at every // mint and transfer. for id := int64(1); id <= supply && int64(len(ids)) < n; id++ { if ownerOf(id) == addr { ids = append(ids, json.NumberNode("", float64(id))) } } } return encode(json.ArrayNode("", ids)) } // maxMintedPage is the most ids MintedJSON looks at in one call. const maxMintedPage = int64(200) // MintedJSON returns who owns the minted planes among the ids offset+1 to // offset+limit, as a JSON array in id order: // // [{"id":3,"owner":"g1..."},{"id":42,"owner":""},...] // // Ids not minted are left out; "owner" is "" for a burned plane. limit is // capped at 200, so four calls (offsets 0, 200, 400, 600) cover the 777, // whatever was minted: planes are drawn at random, minted ids are not a // prefix. It is what the website's grid reads. An empty range is []. func MintedJSON(offset, limit int64) string { if limit > maxMintedPage { limit = maxMintedPage } entries := []*json.Node{} if offset >= 0 && limit > 0 { last := offset + limit if last > supply { last = supply } for id := offset + 1; id <= last; id++ { if !wasMinted(id) { continue } entry := json.Builder(). WriteNumber("id", float64(id)). WriteString("owner", ownerOf(id).String()) entries = append(entries, entry.Node()) } } return encode(json.ArrayNode("", entries)) } // CollectionJSON returns the state of the collection as one JSON object: // // { "name": "gnofly planes", "symbol": "PLANE", // "supply": 777, "minted": 12, "burned": 0, // "price": 77000000, "open": true, "cap": 7, // "royaltyBps": 500, "treasury": "g1...", // "imageBase": "https://gnofly.xyz/nft/collections/planes/", // "tiers": { "common": { "supply": 500, "minted": 8 }, // "rare": { "supply": 200, "minted": 3 }, // "epic": { "supply": 70, "minted": 1 }, // "legendary": { "supply": 7, "minted": 0 } } } // // The output has no whitespace. "minted" counts every mint so far, burned // planes included; "minted" minus "burned" is what exists. func CollectionJSON() string { b := json.Builder(). WriteString("name", tokenName). WriteString("symbol", tokenSymbol). WriteNumber("supply", float64(supply)). WriteNumber("minted", float64(Minted())). WriteNumber("burned", float64(Minted()-Token.TotalSupply())). WriteNumber("price", float64(price)). WriteBool("open", mintOpen). WriteNumber("cap", float64(mintCap)). WriteNumber("royaltyBps", float64(RoyaltyBps())). WriteString("treasury", roles.Treasury().String()). WriteString("imageBase", imageBase). WriteObject("tiers", func(tb *json.NodeBuilder) { for i, tier := range strings.Split(tiers, ",") { tb.WriteObject(tier, func(t *json.NodeBuilder) { t.WriteNumber("supply", float64(tierSupply[i])) t.WriteNumber("minted", float64(tierMinted[i])) }) } }) return encode(b.Node()) } // writePlane writes the nine fields of a plane, in the order of a row, so // that a caller can add fields after them. func writePlane(b *json.NodeBuilder, p plane) { b.WriteNumber("id", float64(p.id)). WriteString("name", p.name). WriteString("model", p.model). WriteString("pilot", p.pilot). WriteString("body", p.body). WriteString("wing", p.wing). WriteString("accent", p.accent). WriteString("tier", p.tier). WriteString("laser", p.laser) } // encode marshals a document built above. It cannot fail on a document // built from the builder, so a failure is a bug and panics. func encode(n *json.Node) string { out, err := json.Marshal(n) if err != nil { panic(err) } return string(out) }
- #12mint.gno
- #13package planes import ( "chain" "chain/banker" "errors" // Only for OriginSend, in Mint. Caller identity always comes from // cur.Previous(), never from this package. "chain/runtime/unsafe" "gno.land/p/nt/grc721/v0" "gno.land/p/onbloc/json/v0" ) // maxBatch is the most planes one Mint call mints. It is a constant, apart // from the per-wallet cap that admins tune with SetMintCap. const maxBatch = int64(7) // Mint mints count planes for the caller, 1 to 7 in one call, drawn at // random among the ids not minted yet (draw.gno), and returns their ids in // the order drawn. Exactly // count times the price must be attached to the transaction (-send // "<count*price>ugnot"); it is forwarded to the treasury of the game realm, // in one send, before the call returns. // // Each id comes out once, while the mint is open. A batch is // minted whole or not at all: one that would take the caller over the // per-wallet cap, or past the last plane, is refused with how many are left. // It must be called directly by a user (maketx call): a call relayed by // another realm or by a maketx run script is refused. That is also what // keeps the draw fair: a contract could otherwise look at the ids it got // and panic to draw again. // // The caller pays the storage of their planes as a deposit on top of the // price, given back on burn: the ledger entries only, the traits stay in the // table (see the numbers in docs/spec.md, section 9.2). func Mint(cur realm, count int64) []int64 { minter := callerOf(0, cur) // Paid-call guard: two checks that are only correct together. // // (a) The caller is a plain user account. Only then is the -send // envelope guaranteed to have landed at this realm's address. A // relaying realm or a maketx run script can attach coins to the // transaction and keep them, while OriginSend still reports them. if !cur.Previous().IsUserCall() { panic(errNotUserCall) } if count < 1 || count > maxBatch { panic(errInvalidCount) } if !mintOpen { panic(errMintClosed) } if n := left(); n < 1 { panic(errSoldOut) } else if count > n { panic("gnofly: only " + itoa(n) + " planes are left to mint") } if left := mintCap - mintedBy(minter); left < 1 { panic(errCapReached) } else if count > left { panic("gnofly: this wallet can mint " + itoa(left) + " more planes, the cap is " + itoa(mintCap)) } // (b) The envelope is exactly count times the price: one coin, the right // denom, the right amount. Anything else would either underpay or // leave coins behind in the realm. total := count * price sent := unsafe.OriginSend() if len(sent) != 1 || sent[0].Denom != payDenom || sent[0].Amount != total { panic("gnofly: wrong payment, send exactly " + itoa(total) + payDenom) } // Forward the payment right away, so that nothing accrues in the realm. // An OriginSend banker can spend the envelope of this call and nothing // else. treasury := roles.Treasury() payment := chain.NewCoins(chain.NewCoin(payDenom, total)) banker.NewBanker(banker.BankerTypeOriginSend, cur).SendCoins(cur.Address(), treasury, payment) ids := make([]int64, 0, count) for i := int64(0); i < count; i++ { p := mustPlane(drawID(minter)) mintCount++ ids = append(ids, p.id) copy(recent[1:], recent[:len(recent)-1]) recent[0] = p.id if err := ledger.Mint(minter, tokenID(p.id)); err != nil { panic(err) } tierMinted[tierIndex(p.tier)]++ chain.Emit("PlaneMinted", "id", itoa(p.id), "minter", minter.String(), "price", itoa(price), "treasury", treasury.String(), ) } mints.Set(minter.String(), mintedBy(minter)+count) return ids } // mintedBy returns how many planes addr minted so far. func mintedBy(addr address) int64 { v := mints.Get(addr.String()) if v == nil { return 0 } return v.(int64) } // The read functions a wallet calls take a grc721.TokenID and return an // error rather than panic, the way Adena calls them: OwnerOf("42") into two // values, TokenURI("42") as the image it shows, TokenMetadata("42") as JSON // for the traits. The errors are made on the call, not stored: a stored // error value costs a kilobyte of deposit (see errors.gno). // TokenMetadata returns the metadata of a minted plane as JSON, built from // the table on every read: the realm stores no metadata per token. // // {"name":"Storm Saint","description":"Plane 42 of 777, ...", // "image":"https://gnofly.xyz/nft/collections/planes/042.png", // "attributes":[{"traitType":"model","value":"delta"}, ...]} // // The keys are the ones Adena reads, traitType included. func TokenMetadata(tid grc721.TokenID) (string, error) { id, err := mintedID(tid) if err != nil { return "", err } p := mustPlane(id) b := json.Builder(). WriteString("name", p.name). WriteString("description", description(p)). WriteString("image", imageURL(id)). WriteArray("attributes", func(ab *json.ArrayBuilder) { for _, t := range [][2]string{ {"model", p.model}, {"pilot", p.pilot}, {"body", p.body}, {"wing", p.wing}, {"accent", p.accent}, {"tier", p.tier}, {"laser", p.laser}, } { ab.WriteObject(func(o *json.NodeBuilder) { o.WriteString("traitType", t[0]).WriteString("value", t[1]) }) } }) return encode(b.Node()), nil } // mintedID reads a token id, "1" to "777", and checks the plane is minted. func mintedID(tid grc721.TokenID) (int64, error) { id := parseID(string(tid)) if ownerOf(id) == "" { return 0, errors.New(errNotMinted) } return id, nil } // parseID reads "1" to "777" in decimal, 0 for anything else. func parseID(s string) int64 { if len(s) == 0 || len(s) > 3 || s[0] == '0' { return 0 } n := int64(0) for i := 0; i < len(s); i++ { if s[i] < '0' || s[i] > '9' { return 0 } n = n*10 + int64(s[i]-'0') } if n > supply { return 0 } return n } // description is one sentence about a plane: "Plane 42 of 777, an epic delta // flown by a gnome." The tier is the only word that may start with a vowel. func description(p plane) string { article := "a " if p.tier == "epic" { article = "an " } s := "Plane " + itoa(p.id) + " of " + itoa(supply) + ", " + article + p.tier + " " + p.model if p.pilot == "gnome" { s += " flown by a gnome" } return s + "." } // Burn destroys a plane. Only its owner can, and nobody can mint it again: // the id stays out of circulation. func Burn(cur realm, id int64) { caller := callerOf(0, cur) if ownerOf(id) != caller { panic(errNotPlaneOwner) } if err := ledger.Burn(tokenID(id)); err != nil { panic(err) } chain.Emit("PlaneBurned", "id", itoa(id), "owner", caller.String()) } // The GRC721 transfer surface. These wrappers hand cur to the caller-scoped // teller, which acts as cur.Previous() and applies it to the private ledger: // a caller moves their own planes and the ones they were approved for, // nothing else. See p/nt/grc721/v0/tellers.gno. // TransferFrom moves plane id from one address to another. The caller must // own it or be approved for it. func TransferFrom(cur realm, from, to address, id int64) { if err := teller.TransferFrom(0, cur, from, to, tokenID(id)); err != nil { panic(err) } } // Approve lets to move plane id once. The caller must own it. An empty // address revokes. func Approve(cur realm, to address, id int64) { if err := teller.Approve(0, cur, to, tokenID(id)); err != nil { panic(err) } } // SetApprovalForAll lets operator move every plane of the caller, or // revokes it. func SetApprovalForAll(cur realm, operator address, approved bool) { if err := teller.SetApprovalForAll(0, cur, operator, approved); err != nil { panic(err) } } // ownerOf returns who owns plane id, or "" when it is not minted. func ownerOf(id int64) address { if id < 1 || id > supply { return "" } owner, err := Token.OwnerOf(tokenID(id)) if err != nil { return "" } return owner } // OwnerOf returns who owns plane tid, or an error when it is not minted. func OwnerOf(tid grc721.TokenID) (address, error) { id, err := mintedID(tid) if err != nil { return "", err } return ownerOf(id), nil } // BalanceOf returns how many planes addr owns. func BalanceOf(addr address) (int64, error) { return Token.BalanceOf(addr) } // TotalSupply returns how many planes exist: minted and not burned. func TotalSupply() int64 { return Token.TotalSupply() } // GetApproved returns the address approved to move plane id, or "" when // there is none. func GetApproved(id int64) address { addr, err := Token.GetApproved(tokenID(id)) if err == grc721.ErrTokenIdNotApproved { return "" } if err != nil { panic(err) } return addr } // IsApprovedForAll reports whether operator may move every plane of owner. func IsApprovedForAll(owner, operator address) bool { return Token.IsApprovedForAll(owner, operator) } // TokenURI returns the image of a minted plane, "<image base><nnn>.png": // what a wallet shows (Adena puts it in an <img>). The metadata is // TokenMetadata, or "<image base><id>.json" on the website. It is computed, // not stored: a mint writes no URI. func TokenURI(tid grc721.TokenID) (string, error) { id, err := mintedID(tid) if err != nil { return "", err } return imageURL(id), nil } // RoyaltyInfo returns who receives the royalty on a sale of plane id at // salePrice, and how much: EIP-2981. func RoyaltyInfo(id int64, salePrice int64) (address, int64) { receiver, amount, err := Royalties.RoyaltyInfo(tokenID(id), salePrice) if err != nil { panic(err) } return receiver, amount } // RoyaltyBps returns the royalty of a resale, in basis points. func RoyaltyBps() int64 { info, ok := Royalties.DefaultRoyalty() if !ok { return 0 } return info.Bps }
- #14planes.gno
- #15package planes import ( "chain" "strconv" "strings" "gno.land/p/nt/bptree/v0" "gno.land/p/nt/grc721/royalty/v0" "gno.land/p/nt/grc721/v0" ) // The read side of the collection, exported for other realms and for // vm/qeval, as GRC721 tokens are on gno.land. Neither type has a mutator: a // Token hands out tellers that act as the calling realm and go through the // ledger's approval checks, Royalty only reads. There is no metadata // extension: the traits are in the table, read with TokenMetadata(tid) and // PlaneJSON(id), and the token URI, the image, is computed by TokenURI(tid). // // planes.TokenMetadata("42") // planes.Token.RealmTeller(0, cur).TransferFrom(0, cur, from, to, "42") var ( Token *grc721.Token // name, symbol, owners, balances, approvals Royalties *royalty.Royalty // EIP-2981 royalty ) // The rest of the state. Everything is unexported and nothing below is ever // returned by reference: the ledgers and the trees are /p/ types with mutator // methods, so handing one out would be handing out write access to the // collection. var ( ledger *grc721.PrivateLedger // the collection, write side: mint, burn teller grc721.Teller // acts as the caller of this realm: transfers and approvals royaltyLedger *royalty.Ledger // royalty, write side mintCount int64 // planes minted so far, burned ones included; the ids left are in pool (draw.gno) price int64 // ugnot, what a mint costs mintOpen bool // whether Mint is accepting calls mintCap int64 // how many planes one wallet may mint, over its lifetime imageBase string // "https://gnofly.xyz/nft/collections/planes/", the image of plane 42 is at <base>042.png mints bptree.BPTree // minter address -> int64, planes minted so far, for the cap tierMinted [4]int64 // planes minted so far per tier, in the order of tiers recent [5]int64 // the last ids minted, newest first, 0 for none, for Render webPath string // "/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/planes", used to build links in Render ) // The collection, and the settings at deploy. const ( supply = int64(777) tokenName = "gnofly planes" tokenSymbol = "PLANE" payDenom = "ugnot" // the only coin planes are sold for defaultPrice = int64(77000000) // 77 GNOT minPrice = int64(1000000) maxPrice = int64(10000000000) defaultMintCap = int64(7) defaultImageBase = "https://gnofly.xyz/nft/collections/planes/" defaultRoyaltyBps = int64(500) // 5% of a resale, to the treasury maxRoyaltyBps = int64(1000) // the most SetRoyaltyBps accepts // Models are what the game client renders, tiers are what the table // says. Both are validated against these lists. models = "prop,biplane,stunt,jet,seaplane,twin,delta,glider,supergnome" pilots = "none,gnome" tiers = "common,rare,epic,legendary" ) // tierSupply is how many planes of each tier the table holds, in the order // of tiers. The tests check it against the table. var tierSupply = [4]int64{500, 200, 70, 7} // tierIndex returns the position of tier in tiers, or -1. func tierIndex(tier string) int { for i, t := range strings.Split(tiers, ",") { if t == tier { return i } } return -1 } // init runs once, when the package is added to the chain. The realm has // nothing to remember about its deployer: it has no role of its own. func init(cur realm) { bootstrap(0, cur) } // bootstrap (re)creates the initial state: the token, its extensions and the // settings. The tests call it to start from a clean slate. rlm is the live // realm of the caller: grc721 records its package path as the home of the // Token. func bootstrap(_ int, rlm realm) { // A table of the wrong shape is refused before anything is written, so // that a bad hand edit fails at publish rather than at the first mint. if first, last := rowID(0), rowID(len(table)-1); first != 1 || last != supply { panic(errBadTable) } Token, ledger = grc721.NewToken(tokenName, tokenSymbol, 0, rlm) // Minted from the ledger: the frame-relative teller is confined to this // realm, which is where it is used. teller = ledger.CallerTeller() Royalties, royaltyLedger = royalty.NewRoyalty(ledger, maxRoyaltyBps) mintCount = 0 resetPool(rlm.PkgPath()) recent = [5]int64{} price = defaultPrice mintOpen = false mintCap = defaultMintCap imageBase = defaultImageBase mints = bptree.BPTree{} tierMinted = [4]int64{} webPath = webPathOf(rlm.PkgPath()) // Under `gno test` the game realm has no treasury yet (see roles.gno): // the tests set one and call bootstrap again. if roles.Treasury().IsValid() { setRoyalty(defaultRoyaltyBps) } } // setRoyalty points the royalty of every plane at the treasury of the game // realm, as it is now, at bps basis points. func setRoyalty(bps int64) { if err := royaltyLedger.SetDefaultRoyalty(roles.Treasury(), bps); err != nil { panic(err) } } // SetMintOpen opens or closes the mint. Admin only. The mint starts closed. func SetMintOpen(cur realm, open bool) { assertAdmin(0, cur) mintOpen = open chain.Emit("MintOpen", "open", boolString(open)) } // SetPrice sets what a mint costs, from 1 to 10000 GNOT. Admin only. It // applies to the next mint. func SetPrice(cur realm, ugnot int64) { assertAdmin(0, cur) if ugnot < minPrice || ugnot > maxPrice { panic(errInvalidPrice) } price = ugnot chain.Emit("PriceSet", "price", itoa(ugnot)) } // SetMintCap sets how many planes one wallet may mint over its lifetime, from // 1 to 777. Admin only. A wallet already over a lowered cap keeps its planes // and mints no more. func SetMintCap(cur realm, n int64) { assertAdmin(0, cur) if n < 1 || n > supply { panic(errInvalidCap) } mintCap = n chain.Emit("MintCapSet", "cap", itoa(n)) } // SetImageBase sets where the images and the metadata of the planes are // served from: the image of plane 42 is <base>042.png and its token URI is // <base>42.json. Admin only. // // It applies at once to every plane: the URLs are computed on read, nothing // is stored per token. func SetImageBase(cur realm, base string) { assertAdmin(0, cur) if !validBase(base) { panic(errInvalidBase) } imageBase = base chain.Emit("ImageBaseSet", "base", base) } // SetRoyaltyBps sets the royalty of a resale, from 0 to 1000 basis points, // and points it at the treasury of the game realm as it is now. Admin only. // // The royalty is advisory, as EIP-2981 is: a marketplace reads RoyaltyInfo // and pays it, the realm cannot enforce it on a transfer. func SetRoyaltyBps(cur realm, bps int64) { assertAdmin(0, cur) if bps < 0 || bps > maxRoyaltyBps { panic(errInvalidRoyalty) } setRoyalty(bps) } // Minted returns how many planes were minted so far, burned ones included. // Planes are drawn at random, so it says nothing of which ids. The // settings (price, open, cap, image base, royalty) are read with // CollectionJSON: every exported function costs storage at deploy, measured // at about 650 bytes each, so there is no getter per setting. func Minted() int64 { return mintCount } // webPathOf turns "gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/planes" into "/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/nfts/planes". func webPathOf(pkgPath string) string { for i := 0; i < len(pkgPath); i++ { if pkgPath[i] == '/' { return pkgPath[i:] } } return "" } // imageURL returns where the image of plane id is: <image base><id>.png, // the id on three digits, "042.png", as the image files are named. The token // URI keeps the plain id, "42.json". func imageURL(id int64) string { return imageBase + pad3(id) + ".png" } // pad3 writes an id of 1 to 777 on three digits: 7 -> "007", 42 -> "042". func pad3(id int64) string { s := itoa(id) for len(s) < 3 { s = "0" + s } return s } func itoa(n int64) string { return strconv.FormatInt(n, 10) } func boolString(b bool) string { if b { return "true" } return "false" }
- #16render.gno
- #17package planes import ( "strconv" "strings" ) // Render returns the state of the collection as markdown, for gnoweb: // // "" the collection: minted, price, tiers, the last mints // "plane/<id>" one plane: traits, owner // "player/<addr>" the planes of one address // // Everything printed here is a row of the table, whose charset the tests // pin, a setting validated when it was written, or an address the chain gave // the realm. The two caller-supplied values, an id and an address, are // printed only once parsed and found valid. Nothing needs markdown escaping. // No images: the planes are drawn by the game and by the website. func Render(path string) string { switch { case path == "": return renderHome() case strings.HasPrefix(path, "plane/"): if id, err := strconv.ParseInt(strings.TrimPrefix(path, "plane/"), 10, 64); err == nil { if p, ok := getPlane(id); ok { return renderPlane(p) } } case strings.HasPrefix(path, "player/"): if addr := address(strings.TrimPrefix(path, "player/")); validAddress(addr) { return renderPlayer(addr) } } return "# gnofly planes\n\nPage not found. Go back to the [collection](" + link("") + ").\n" } // link returns the gnoweb URL of a Render path of this realm. func link(path string) string { if path == "" { return webPath } return webPath + ":" + path } func renderHome() string { var b strings.Builder b.WriteString("# gnofly planes\n\n") b.WriteString("777 planes to fly in gnofly, a multiplayer plane game. Each one is a GRC721 token with a name,\n") b.WriteString("a model, three colours, a tier and a laser, drawn from a table written once and for all.\n") b.WriteString("Mint up to 7 at once with `Mint` and count times the price attached, then pick one in the hangar of the game.\n\n") b.WriteString("| | |\n|---|---|\n") b.WriteString("| Minted | " + itoa(Minted()) + " of " + itoa(supply) + " |\n") b.WriteString("| Burned | " + itoa(Minted()-Token.TotalSupply()) + " |\n") b.WriteString("| Price | " + gnot(price) + " |\n") b.WriteString("| Mint open | " + yesNo(mintOpen) + " |\n") b.WriteString("| Per wallet | " + itoa(mintCap) + " |\n") b.WriteString("| Royalty | " + percent(RoyaltyBps()) + " to the treasury |\n") b.WriteString("| Treasury | " + roles.Treasury().String() + " |\n\n") b.WriteString("## Tiers\n\n") b.WriteString("| Tier | Planes | Minted |\n|---|---|---|\n") for i, tier := range strings.Split(tiers, ",") { b.WriteString("| " + tier + " | " + itoa(tierSupply[i]) + " | " + itoa(tierMinted[i]) + " |\n") } b.WriteString("\n## Recent mints\n\n") recent := 0 for _, id := range recentIDs() { owner := ownerOf(id) if owner == "" { continue // burned } if recent == 0 { b.WriteString("| Plane | Tier | Owner |\n|---|---|---|\n") } p := mustPlane(id) b.WriteString("| " + planeLink(p) + " | " + p.tier + " | " + playerLink(owner) + " |\n") recent++ } if recent == 0 { b.WriteString("No plane is minted yet.\n") } return b.String() } func renderPlane(p plane) string { var b strings.Builder b.WriteString("# " + p.name + "\n\n") b.WriteString("Plane " + itoa(p.id) + " of " + itoa(supply) + ", " + p.tier + ".\n\n") b.WriteString("| | |\n|---|---|\n") b.WriteString("| Model | " + p.model + " |\n") b.WriteString("| Pilot | " + p.pilot + " |\n") b.WriteString("| Body | `" + p.body + "` |\n") b.WriteString("| Wing | `" + p.wing + "` |\n") b.WriteString("| Accent | `" + p.accent + "` |\n") b.WriteString("| Laser | `" + p.laser + "` |\n") b.WriteString("| Tier | " + p.tier + " |\n") owner := ownerOf(p.id) switch { case owner == "" && wasMinted(p.id): b.WriteString("| Owner | burned |\n") case owner == "": b.WriteString("| Owner | not minted yet |\n") default: b.WriteString("| Owner | " + playerLink(owner) + " |\n") b.WriteString("| Metadata | `" + imageBase + itoa(p.id) + ".json` |\n") } b.WriteString("\n[Collection](" + link("") + ")\n") return b.String() } func renderPlayer(addr address) string { var b strings.Builder b.WriteString("# Pilot " + addr.String() + "\n\n") n, _ := Token.BalanceOf(addr) if n == 0 { b.WriteString("This address owns no plane.\n") } else { b.WriteString(itoa(n) + " plane" + plural(n) + ", minted " + itoa(mintedBy(addr)) + " of " + itoa(mintCap) + " allowed.\n\n") b.WriteString("| Plane | Model | Pilot | Tier |\n|---|---|---|---|\n") found := int64(0) for id := int64(1); id <= supply && found < n; id++ { if ownerOf(id) != addr { continue } p := mustPlane(id) b.WriteString("| " + planeLink(p) + " | " + p.model + " | " + p.pilot + " | " + p.tier + " |\n") found++ } } b.WriteString("\n[Collection](" + link("") + ")\n") return b.String() } // planeLink is "[42 Storm Saint](.../plane/42)". func planeLink(p plane) string { return "[" + itoa(p.id) + " " + p.name + "](" + link("plane/"+itoa(p.id)) + ")" } // playerLink is "[g1...](.../player/g1...)". func playerLink(addr address) string { return "[" + addr.String() + "](" + link("player/"+addr.String()) + ")" } // gnot formats an amount of ugnot in GNOT, without trailing zeros: // 77000000 gives "77 GNOT", 9500000 gives "9.5 GNOT". func gnot(ugnot int64) string { whole, frac := ugnot/1000000, ugnot%1000000 if frac == 0 { return itoa(whole) + " GNOT" } decimals := itoa(1000000 + frac)[1:] // all six of them, zeros included end := len(decimals) for decimals[end-1] == '0' { end-- } return itoa(whole) + "." + decimals[:end] + " GNOT" } // percent formats basis points as a percentage, without trailing zeros: // 500 gives "5%", 250 gives "2.5%", 1 gives "0.01%". func percent(bps int64) string { whole, frac := bps/100, bps%100 switch { case frac == 0: return itoa(whole) + "%" case frac%10 == 0: return itoa(whole) + "." + itoa(frac/10) + "%" case frac < 10: return itoa(whole) + ".0" + itoa(frac) + "%" } return itoa(whole) + "." + itoa(frac) + "%" } func plural(n int64) string { if n == 1 { return "" } return "s" } func yesNo(b bool) string { if b { return "yes" } return "no" } // recentIDs returns the last ids minted, newest first. func recentIDs() []int64 { var ids []int64 for _, id := range recent { if id != 0 { ids = append(ids, id) } } return ids }
- #18roles.gno
- #19package planes import "gno.land/r/g1t2kg2vtr3fukg43eujkn6x53gfdyakhngt4sfd/gnofly/game/v0" // The planes realm keeps no roles of its own. Who administers it and where // its money goes are the answers of the game realm, asked again at every // call: an admin removed there is refused here in the same block, and a // treasury moved there receives the next mint. // authority is the set of questions this realm asks about roles. type authority interface { IsAdmin(addr address) bool Treasury() address } // gameRoles answers with the roles of the game realm. type gameRoles struct{} func (gameRoles) IsAdmin(addr address) bool { return game.IsAdmin(addr) } func (gameRoles) Treasury() address { return game.Treasury() } // roles is the authority of this realm: the game realm, always. // // It is a variable for one reason. Under `gno test` an imported realm is // initialized without a deployer, and a test of this package has no way to // become an admin of the game realm, so the tests put their own answers // here. Nothing outside the test files assigns it, and there is no setter. var roles authority = gameRoles{} // callerOf returns the verified caller of a crossing function. rlm must be // the cur of the crossing function calling this helper: a stale or forged // realm value fails IsCurrent, and Previous is only meaningful on a live one. // // It takes the realm in second position on purpose, like p/nt/ownable does: // a function whose first parameter is a realm is a crossing function. func callerOf(_ int, rlm realm) address { if !rlm.IsCurrent() { panic(errSpoofedRealm) } return rlm.Previous().Address() } // assertAdmin panics unless the caller is an admin of the game realm, and // returns the caller. func assertAdmin(_ int, rlm realm) address { caller := callerOf(0, rlm) if !roles.IsAdmin(caller) { panic(errNotAdmin) } return caller }
- #20rows.gno
- #21package planes import ( "strings" "gno.land/p/nt/grc721/v0" ) // plane is one row of the table: what a plane looks like. Nothing here is // stored per token, the table is the only copy. type plane struct { id int64 name string model string // a model the client draws, see models pilot string // none or gnome body string // colours, "#rrggbb"; on the super-gnome: cape, suit, emblem wing string accent string tier string // common, rare, epic, legendary laser string // the colour of its shots, "#rrggbb" } // The table is one string of 777 lines, // "id|name|model|pilot|body|wing|accent|tier|laser", // in id order (see table.gno). It is kept as a string and read in place // because storage is paid per byte at deploy: 777 structs would cost about // ten times as much as the text, and a plane is read far less often than it // is paid for. // // A row is found by bisection on the offsets of the string: from any offset, // the start of its line is at most a line's length back. Ten steps of a // hundred bytes each, where walking the lines from the top would be forty // thousand. // row returns the line of plane id, or "" when there is no such row. func row(id int64) string { if id < 1 || id > supply { return "" } lo, hi := 0, len(table)-1 for lo <= hi { mid := (lo + hi) / 2 start, end := lineAt(mid) n := idAt(start, end) switch { case n == id: return table[start:end] case n < id: lo = end + 1 default: hi = start - 1 } } return "" } // lineAt returns the bounds of the line containing offset i: start is its // first byte, end the offset of its newline, or len(table) for the last line. func lineAt(i int) (start, end int) { start = i for start > 0 && table[start-1] != '\n' { start-- } end = i for end < len(table) && table[end] != '\n' { end++ } return start, end } // rowID reads the id of the line containing offset i, or 0 when the line // does not start with a number. func rowID(i int) int64 { start, end := lineAt(i) return idAt(start, end) } // idAt reads the id at the start of the line table[start:end]. func idAt(start, end int) int64 { n := int64(0) for j := start; j < end; j++ { c := table[j] if c == '|' { return n } if c < '0' || c > '9' || j-start > 3 { return 0 } n = n*10 + int64(c-'0') } return 0 } // parsePlane turns a row into a plane. It checks the shape of the row, not // its values: those are the table's promise, checked by the tests. func parsePlane(line string) (plane, bool) { f := strings.Split(line, "|") if len(f) != 9 { return plane{}, false } id := int64(0) for i := 0; i < len(f[0]); i++ { id = id*10 + int64(f[0][i]-'0') } return plane{id: id, name: f[1], model: f[2], pilot: f[3], body: f[4], wing: f[5], accent: f[6], tier: f[7], laser: f[8]}, true } // getPlane returns plane id from the table, or false when the id is out of // range. func getPlane(id int64) (plane, bool) { line := row(id) if line == "" { return plane{}, false } p, ok := parsePlane(line) if !ok { panic(errCorruptRow) } return p, true } // mustPlane returns plane id from the table, or panics. func mustPlane(id int64) plane { p, ok := getPlane(id) if !ok { panic(errUnknownPlane) } return p } // tokenID is the GRC721 id of plane id: its number, in decimal. func tokenID(id int64) grc721.TokenID { return grc721.TokenID(itoa(id)) } // valid reports whether p respects every rule of the table. The tests run it // on all 777 rows; the realm trusts the table after that, which is what // makes the hand-built JSON and markdown of this realm safe. func (p plane) valid() bool { return p.id >= 1 && p.id <= supply && validName(p.name) && oneOf(p.model, models) && oneOf(p.pilot, pilots) && validColor(p.body) && validColor(p.wing) && validColor(p.accent) && validColor(p.laser) && oneOf(p.tier, tiers) } // validName reports whether s matches [A-Za-z0-9 -]{1,24}. func validName(s string) bool { if len(s) == 0 || len(s) > 24 { return false } for i := 0; i < len(s); i++ { c := s[i] if !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != ' ' && c != '-' { return false } } return true } // validColor reports whether s is "#rrggbb" with lowercase hex digits. func validColor(s string) bool { if len(s) != 7 || s[0] != '#' { return false } for i := 1; i < len(s); i++ { c := s[i] if !(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') { return false } } return true } // validBase reports whether s can be an image base: an https URL ending in // "/", 12 to 200 characters of [A-Za-z0-9./_-:]. The charset keeps it safe // in JSON and markdown without escaping. func validBase(s string) bool { if len(s) < 12 || len(s) > 200 || !strings.HasPrefix(s, "https://") || s[len(s)-1] != '/' { return false } for i := 0; i < len(s); i++ { c := s[i] if !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '.' && c != '/' && c != '_' && c != '-' && c != ':' { return false } } return true } // validAddress reports whether addr is a valid address in its canonical, // lowercase form, the only form the game realm and this one key on. func validAddress(addr address) bool { return addr.IsValid() && addr[0] == 'g' } // oneOf reports whether s is one of the comma-separated words of list. func oneOf(s, list string) bool { for _, w := range strings.Split(list, ",") { if s == w { return true } } return false }
- #22table.gno
- #23// Generated by scripts/planes-table.ts with the seed "gnofly-planes-v1": // // bun run scripts/planes-table.ts // // It can be edited by hand afterwards, as long as every rule below holds. The // tests of this package check them, and init refuses a table of the wrong // length. package planes // table holds the traits of the 777 planes, one per line, in id order: // // id|name|model|pilot|body|wing|accent|tier|laser // // Ids run from 1 to 777 with no gap. Names are unique and match // [A-Za-z0-9 -]{1,24}. Tiers are common (500), rare (200), epic (70) and // legendary (7). Models are those the client draws: prop, biplane, stunt for // a common plane, jet, seaplane, twin for a rare one, delta, glider for an epic // one, any of them for a legendary one, and supergnome for id 777 alone. Pilot // is none or gnome; the super-gnome is the gnome, its pilot is none. Colours // are #rrggbb in lowercase, the first three all different; on the // super-gnome they are its cape, its suit and its emblem. The laser is the // colour of the shots the plane fires; it comes last, added after the first // version of the table. // // It is one string, parsed on read: 777 rows as structs would cost about ten // times the storage deposit at deploy. See rows.gno for the parser. const table = `1|Storm Sentinel|delta|gnome|#172554|#27272a|#ff4d6d|epic|#ff9e00 2|Windy Thrush|biplane|none|#ddd5c7|#8c7b6b|#f2cc8f|common|#ffb347 3|Humble Bucket|prop|none|#b5a27a|#4f5d75|#c9a227|common|#ffc971 4|Lonely Pony|prop|none|#c2b280|#5c5c5c|#588157|common|#ffe680 5|Tin Pelican|biplane|gnome|#b5a27a|#9a8c98|#f4f1de|common|#ffb347 6|Patched Tarmac|stunt|none|#b5a27a|#5c5c5c|#e07a5f|common|#ffd166 7|Rusty Wren|prop|none|#b08968|#7a6a53|#bc6c25|common|#ffd166 8|Specter Monarch|delta|gnome|#2e1065|#581c87|#ff6a00|epic|#ff006e 9|Dusty Robin|prop|none|#9c8f6e|#6f4e37|#d08c60|common|#ffd166 10|Tidy Puffin|prop|none|#ddd5c7|#56604a|#e07a5f|common|#fff1c1 11|Steady Pigeon|prop|none|#c2b280|#8c7b6b|#3d405b|common|#ffd166 12|Cheap Gull|prop|gnome|#9c8f6e|#5c5c5c|#e9c46a|common|#ffc971 13|Weary Rook|biplane|none|#b08968|#5e6472|#bc6c25|common|#ffb347 14|Patched Pelican|prop|none|#6b705c|#5e6472|#f2cc8f|common|#ffe680 15|Eclipse Wraith|delta|gnome|#3b0764|#312e81|#ff6a00|epic|#c77dff 16|Weary Dove|biplane|gnome|#8a9a5b|#a3a380|#d08c60|common|#ffc971 17|Shadow Banshee|delta|gnome|#450a0a|#7f1d1d|#00f5ff|epic|#ff006e 18|Spare Mule|stunt|gnome|#7d8597|#56604a|#a44a3f|common|#ffd166 19|Cloudy Heron|stunt|gnome|#a89f91|#a3a380|#588157|common|#ffb347 20|Onyx Shrike|jet|gnome|#c1121f|#e2e8f0|#000000|rare|#ff66c4 21|Icarus Prime|glider|gnome|#fde68a|#f59e0b|#7c2d12|legendary|#ff7a00 22|Canvas Starling|stunt|none|#9b7e6b|#4f5d75|#f2cc8f|common|#ffe680 23|Bronze Eagle|jet|none|#7c3aed|#f8fafc|#22d3ee|rare|#ff66c4 24|Patched Crane|stunt|none|#a89f91|#4f5d75|#f2cc8f|common|#ffc971 25|Scruffy Quail|prop|none|#ddd5c7|#7a6a53|#c9a227|common|#ffe680 26|Spare Rook|prop|gnome|#9c8f6e|#5c5c5c|#bc6c25|common|#ffe680 27|Bronze Kestrel|jet|none|#2563eb|#111827|#ffffff|rare|#9d8cff 28|Golden Vulture|seaplane|gnome|#c1121f|#f1f5f9|#f472b6|rare|#4dd2ff 29|Ivory Falcon|seaplane|gnome|#c1121f|#111827|#000000|rare|#4dd2ff 30|Azure Albatross|seaplane|gnome|#1d4ed8|#111827|#fbbf24|rare|#9d8cff 31|Muddy Robin|biplane|none|#6b705c|#56604a|#a44a3f|common|#fff1c1 32|Humble Lark|biplane|none|#8a9a5b|#4f5d75|#a44a3f|common|#ffe680 33|Steady Hangar|biplane|none|#6b705c|#4f5d75|#d08c60|common|#fff1c1 34|Patient Starling|prop|gnome|#b08968|#56604a|#c9a227|common|#fff1c1 35|Little Wagon|prop|none|#a89f91|#5e6472|#e9c46a|common|#ffb347 36|Honest Crow|stunt|none|#b08968|#5c5c5c|#3d405b|common|#ffc971 37|Thrifty Dove|prop|none|#6b705c|#7a6a53|#d08c60|common|#ffe680 38|Rural Puffin|stunt|none|#9c8f6e|#6f4e37|#e9c46a|common|#ffc971 39|Faded Puffin|prop|gnome|#aab7b8|#9a8c98|#3d405b|common|#ffe680 40|Patched Lark|stunt|none|#7d8597|#5c5c5c|#c9a227|common|#ffe680 41|Cobalt Vulture|seaplane|gnome|#2563eb|#111827|#a3e635|rare|#ff8c1a 42|Electric Raven|jet|gnome|#c1121f|#f8fafc|#fb923c|rare|#ff66c4 43|Midnight Baroness|seaplane|none|#2d0a31|#4a044e|#f0abfc|legendary|#f0abfc 44|Muddy Puffin|prop|none|#a89f91|#9a8c98|#f4f1de|common|#ffc971 45|Grey Finch|stunt|none|#8a9a5b|#6b705c|#d08c60|common|#fff1c1 46|Patched Teal|stunt|none|#6b705c|#5e6472|#c9a227|common|#ffc971 47|Quiet Gull|biplane|none|#aab7b8|#8c7b6b|#e07a5f|common|#fff1c1 48|Silver Lancer|seaplane|none|#c1121f|#fde68a|#000000|rare|#ff8c1a 49|Thunder Reaper|glider|gnome|#1e1b4b|#14532d|#39ff14|epic|#b8ff00 50|Cheap Tern|prop|none|#c2b280|#a3a380|#f4f1de|common|#ffb347 51|Sunday Heron|stunt|none|#aab7b8|#56604a|#d08c60|common|#ffd166 52|Copper Osprey|jet|gnome|#facc15|#0f172a|#000000|rare|#ff66c4 53|Comet Tempest|glider|gnome|#2e1065|#14532d|#00f5ff|epic|#f72585 54|Cheap Mule|prop|none|#8d8d8d|#4f5d75|#a44a3f|common|#fff1c1 55|Spare Windsock|prop|gnome|#a89f91|#a3a380|#e07a5f|common|#ffc971 56|Spotted Starling|stunt|none|#8d8d8d|#5e6472|#e9c46a|common|#ffe680 57|Sleepy Crow|biplane|gnome|#8d8d8d|#56604a|#f2cc8f|common|#ffe680 58|Sandy Tarmac|biplane|none|#8a9a5b|#56604a|#d08c60|common|#ffd166 59|Steady Tern|prop|none|#b5a27a|#5e6472|#a44a3f|common|#ffb347 60|Phantom Titan|delta|gnome|#172554|#14532d|#00f5ff|epic|#39ff14 61|Phantom Oracle|glider|gnome|#042f2e|#1e3a8a|#4cc9f0|epic|#7df9ff 62|Quiet Hangar|stunt|gnome|#aab7b8|#5c5c5c|#f4f1de|common|#fff1c1 63|Lonely Tern|stunt|gnome|#b08968|#4f5d75|#f4f1de|common|#fff1c1 64|Sandy Lark|biplane|none|#8a9a5b|#56604a|#e07a5f|common|#ffc971 65|Brave Owl|prop|none|#6b705c|#5c5c5c|#f2cc8f|common|#ffd166 66|Canvas Hangar|stunt|none|#c2b280|#a3a380|#d08c60|common|#ffb347 67|Spotted Pony|biplane|none|#ddd5c7|#a3a380|#f4f1de|common|#ffd166 68|Electric Falcon|jet|none|#f97316|#fef3c7|#ffffff|rare|#9d8cff 69|Bronze Spitfire|seaplane|gnome|#1d4ed8|#1e293b|#a3e635|rare|#9d8cff 70|Rural Thrush|stunt|none|#9b7e6b|#56604a|#3d405b|common|#fff1c1 71|Ivory Mustang|jet|gnome|#15803d|#1e293b|#fbbf24|rare|#9d8cff 72|Patient Heron|biplane|none|#b5a27a|#6b705c|#3d405b|common|#ffe680 73|Humble Wagon|prop|none|#7d8597|#6b705c|#588157|common|#ffb347 74|Honest Finch|biplane|gnome|#b08968|#7a6a53|#c9a227|common|#ffe680 75|Amber Kingfisher|twin|gnome|#be185d|#e2e8f0|#fbbf24|rare|#ff4d4d 76|Sunset Kestrel|seaplane|gnome|#0891b2|#f8fafc|#22d3ee|rare|#9d8cff 77|Ember Saint|delta|gnome|#042f2e|#1e293b|#ff6a00|epic|#f72585 78|Spare Robin|prop|none|#b08968|#56604a|#e07a5f|common|#ffb347 79|Steady Snipe|stunt|none|#9c8f6e|#6f4e37|#a44a3f|common|#fff1c1 80|Plain Stork|prop|none|#8a9a5b|#5c5c5c|#d08c60|common|#ffe680 81|Aurora Reaper|delta|gnome|#042f2e|#312e81|#ff6a00|epic|#7df9ff 82|Muddy Duck|stunt|none|#ddd5c7|#9a8c98|#e9c46a|common|#ffb347 83|Midnight Saint|delta|gnome|#172554|#134e4a|#00f5ff|epic|#f72585 84|Early Pelican|prop|none|#8a9a5b|#7a6a53|#f2cc8f|common|#ffd166 85|Lucky Starling|stunt|gnome|#9c8f6e|#a3a380|#588157|common|#ffc971 86|Sleepy Wagon|stunt|none|#a89f91|#5e6472|#588157|common|#fff1c1 87|Midnight Tempest|delta|gnome|#4a0404|#1e293b|#39ff14|epic|#ff9e00 88|Amber Peregrine|seaplane|gnome|#f97316|#0f172a|#ef4444|rare|#ffe14d 89|Tin Quail|biplane|none|#7d8597|#a3a380|#e9c46a|common|#ffc971 90|Plasma Warden|glider|gnome|#450a0a|#1e3a8a|#39ff14|epic|#c77dff 91|Spare Lark|prop|none|#ddd5c7|#6b705c|#3d405b|common|#ffc971 92|Crimson Hobby|seaplane|gnome|#15803d|#0f172a|#f472b6|rare|#ff8c1a 93|Eclipse Monarch|glider|gnome|#0b1020|#134e4a|#f72585|epic|#00f5ff 94|Emerald Raven|seaplane|gnome|#facc15|#111827|#fb923c|rare|#7cff6b 95|Indigo Buzzard|twin|none|#be185d|#fde68a|#000000|rare|#9d8cff 96|Tidy Pigeon|prop|none|#8d8d8d|#4f5d75|#e07a5f|common|#fff1c1 97|Rural Rook|prop|none|#b08968|#5e6472|#bc6c25|common|#ffd166 98|Rainy Rook|prop|none|#9b7e6b|#56604a|#e07a5f|common|#fff1c1 99|Cheap Finch|prop|none|#b08968|#56604a|#f4f1de|common|#ffc971 100|Early Tern|stunt|none|#6b705c|#8c7b6b|#3d405b|common|#ffe680 101|Azure Osprey|seaplane|gnome|#0891b2|#fde68a|#ffffff|rare|#9d8cff 102|Patient Puffin|biplane|none|#aab7b8|#5c5c5c|#3d405b|common|#ffc971 103|Spare Stork|stunt|gnome|#c2b280|#5c5c5c|#588157|common|#ffd166 104|Thunder Vanguard|glider|gnome|#052e16|#1e3a8a|#00f5ff|epic|#39ff14 105|Lonely Swift|prop|gnome|#8a9a5b|#5c5c5c|#f2cc8f|common|#ffd166 106|Rainy Lantern|prop|gnome|#6b705c|#5c5c5c|#c9a227|common|#ffe680 107|Second Wren|biplane|none|#8a9a5b|#8c7b6b|#c9a227|common|#fff1c1 108|Cloudy Mallard|stunt|none|#c2b280|#6b705c|#bc6c25|common|#ffb347 109|Tin Starling|stunt|none|#9c8f6e|#6f4e37|#e9c46a|common|#ffe680 110|Rainy Bucket|biplane|none|#6b705c|#5e6472|#f4f1de|common|#ffe680 111|Honest Thrush|stunt|none|#8a9a5b|#a3a380|#588157|common|#ffd166 112|Sky Marshal|delta|gnome|#e5e7eb|#9ca3af|#0ea5e9|legendary|#38bdf8 113|Windy Rook|prop|none|#c2b280|#4f5d75|#d08c60|common|#ffd166 114|Rural Pony|biplane|none|#9b7e6b|#5c5c5c|#e9c46a|common|#ffb347 115|Quiet Stork|biplane|none|#aab7b8|#5e6472|#588157|common|#ffb347 116|Slow Crow|prop|none|#aab7b8|#56604a|#f2cc8f|common|#ffe680 117|Brave Windsock|biplane|none|#9c8f6e|#56604a|#e9c46a|common|#fff1c1 118|Steady Crane|biplane|none|#7d8597|#8c7b6b|#bc6c25|common|#ffb347 119|Thrifty Windsock|prop|gnome|#9b7e6b|#8c7b6b|#bc6c25|common|#fff1c1 120|Canvas Sparrow|stunt|none|#b08968|#7a6a53|#c9a227|common|#ffc971 121|Faded Heron|stunt|none|#8d8d8d|#a3a380|#588157|common|#ffd166 122|Rainy Jay|prop|none|#8a9a5b|#6f4e37|#e07a5f|common|#ffe680 123|Brave Kettle|prop|none|#b08968|#4f5d75|#3d405b|common|#fff1c1 124|Rainy Wagon|prop|gnome|#ddd5c7|#6f4e37|#bc6c25|common|#ffb347 125|Cloudy Finch|prop|none|#9b7e6b|#4f5d75|#f2cc8f|common|#fff1c1 126|Gentle Mallard|stunt|gnome|#b08968|#6f4e37|#e9c46a|common|#ffd166 127|Lonely Barrel|biplane|none|#9c8f6e|#a3a380|#d08c60|common|#ffc971 128|Second Heron|prop|none|#c2b280|#8c7b6b|#e9c46a|common|#ffb347 129|Lonely Owl|biplane|none|#8a9a5b|#5c5c5c|#e9c46a|common|#fff1c1 130|Azure Peregrine|twin|gnome|#c1121f|#0f172a|#22d3ee|rare|#ffe14d 131|Specter Tempest|glider|gnome|#052e16|#134e4a|#39ff14|epic|#39ff14 132|Tin Crow|prop|none|#9c8f6e|#56604a|#bc6c25|common|#ffb347 133|Patched Crow|stunt|none|#b5a27a|#8c7b6b|#3d405b|common|#ffb347 134|Windy Owl|stunt|none|#7d8597|#a3a380|#f2cc8f|common|#ffd166 135|Ruby Peregrine|twin|gnome|#be185d|#fde68a|#000000|rare|#ffe14d 136|Early Barrel|stunt|none|#7d8597|#6f4e37|#a44a3f|common|#ffc971 137|Foggy Sparrow|prop|none|#9c8f6e|#7a6a53|#3d405b|common|#fff1c1 138|Dusty Crow|prop|none|#9c8f6e|#6b705c|#bc6c25|common|#ffd166 139|Weary Lantern|biplane|none|#a89f91|#6f4e37|#f2cc8f|common|#ffc971 140|Rainy Robin|stunt|none|#9c8f6e|#a3a380|#f4f1de|common|#fff1c1 141|Sturdy Pelican|biplane|none|#aab7b8|#5e6472|#3d405b|common|#fff1c1 142|Faded Robin|biplane|gnome|#ddd5c7|#7a6a53|#e9c46a|common|#fff1c1 143|Second Dove|biplane|none|#c2b280|#5e6472|#e07a5f|common|#ffd166 144|Golden Gannet|seaplane|none|#facc15|#fde68a|#f472b6|rare|#7cff6b 145|Sunday Sparrow|stunt|gnome|#b5a27a|#8c7b6b|#3d405b|common|#ffc971 146|Rusty Lantern|prop|none|#6b705c|#6f4e37|#c9a227|common|#ffe680 147|Brave Dove|stunt|none|#7d8597|#9a8c98|#e9c46a|common|#ffd166 148|Honest Mallard|stunt|none|#7d8597|#8c7b6b|#d08c60|common|#ffb347 149|Little Duck|prop|gnome|#aab7b8|#9a8c98|#a44a3f|common|#fff1c1 150|Frost Monarch|delta|gnome|#2e1065|#134e4a|#39ff14|epic|#b8ff00 151|Cheap Barrel|stunt|none|#9c8f6e|#5c5c5c|#f4f1de|common|#ffc971 152|Coral Kestrel|seaplane|none|#15803d|#f1f5f9|#ef4444|rare|#9d8cff 153|Brave Quail|prop|none|#6b705c|#5e6472|#e07a5f|common|#ffb347 154|Plain Windsock|prop|gnome|#a89f91|#5e6472|#e07a5f|common|#ffe680 155|Sandy Tern|prop|none|#9c8f6e|#7a6a53|#e07a5f|common|#ffc971 156|Omega Titan|glider|gnome|#052e16|#7f1d1d|#4cc9f0|epic|#ff9e00 157|Sleepy Barrel|prop|none|#b08968|#6f4e37|#d08c60|common|#ffe680 158|Indigo Eagle|seaplane|none|#f97316|#e2e8f0|#a3e635|rare|#ff4d4d 159|Early Crane|prop|gnome|#a89f91|#6b705c|#d08c60|common|#ffe680 160|Saffron Raven|seaplane|gnome|#0891b2|#e2e8f0|#a3e635|rare|#9d8cff 161|Sandy Wagon|stunt|none|#a89f91|#5c5c5c|#d08c60|common|#ffc971 162|Grey Sparrow|stunt|none|#aab7b8|#6b705c|#d08c60|common|#fff1c1 163|Plain Gull|prop|none|#b08968|#6b705c|#e07a5f|common|#ffd166 164|Canvas Snipe|stunt|gnome|#b08968|#6b705c|#d08c60|common|#ffb347 165|Eclipse Banshee|delta|gnome|#172554|#581c87|#ffd60a|epic|#39ff14 166|Loyal Windsock|biplane|none|#c2b280|#5c5c5c|#588157|common|#fff1c1 167|Quiet Puffin|biplane|none|#b5a27a|#6b705c|#e07a5f|common|#ffd166 168|Jade Lancer|seaplane|none|#2563eb|#f1f5f9|#ffffff|rare|#ffe14d 169|Jade Spitfire|seaplane|gnome|#c1121f|#fef3c7|#000000|rare|#ff4d4d 170|Patient Lantern|prop|none|#c2b280|#a3a380|#f2cc8f|common|#ffd166 171|Sleepy Finch|stunt|gnome|#9c8f6e|#56604a|#f4f1de|common|#fff1c1 172|Teal Viper|twin|gnome|#be185d|#111827|#000000|rare|#7cff6b 173|Plasma Valkyrie|delta|gnome|#4a0404|#7f1d1d|#00f5ff|epic|#7df9ff 174|Thrifty Barrel|prop|gnome|#a89f91|#6f4e37|#f2cc8f|common|#ffd166 175|Emerald Eagle|seaplane|none|#0891b2|#fde68a|#000000|rare|#ff66c4 176|Grey Windsock|biplane|none|#c2b280|#6b705c|#bc6c25|common|#ffe680 177|Electric Shrike|twin|none|#facc15|#1e293b|#000000|rare|#4dd2ff 178|Rainy Magpie|stunt|none|#aab7b8|#9a8c98|#f2cc8f|common|#fff1c1 179|Phantom Reaper|delta|gnome|#042f2e|#312e81|#ff4d6d|epic|#00f5ff 180|Eclipse Saint|glider|gnome|#052e16|#312e81|#f72585|epic|#39ff14 181|Windy Robin|prop|none|#9b7e6b|#56604a|#f2cc8f|common|#fff1c1 182|Little Hangar|prop|none|#8a9a5b|#5c5c5c|#f2cc8f|common|#ffc971 183|Spare Duck|biplane|none|#8d8d8d|#7a6a53|#f2cc8f|common|#ffc971 184|Humble Kite|biplane|none|#aab7b8|#4f5d75|#bc6c25|common|#ffe680 185|Cloudy Windsock|prop|none|#c2b280|#5c5c5c|#f2cc8f|common|#ffd166 186|Steady Dove|stunt|none|#6b705c|#9a8c98|#f2cc8f|common|#ffc971 187|Muddy Crane|prop|none|#c2b280|#56604a|#f2cc8f|common|#ffc971 188|Omega Warden|glider|gnome|#2e1065|#581c87|#ff6a00|epic|#ff006e 189|Muddy Stork|biplane|none|#b08968|#5c5c5c|#c9a227|common|#ffd166 190|Ruby Kestrel|seaplane|none|#f97316|#f1f5f9|#ef4444|rare|#9d8cff 191|Royal Caracara|jet|gnome|#c1121f|#111827|#ef4444|rare|#ffe14d 192|Gentle Snipe|stunt|none|#b08968|#5e6472|#588157|common|#fff1c1 193|Indigo Vulture|jet|none|#c1121f|#f8fafc|#ef4444|rare|#7cff6b 194|Grey Teal|biplane|none|#b08968|#6f4e37|#3d405b|common|#ffb347 195|Azure Merlin|twin|gnome|#ea580c|#0f172a|#fbbf24|rare|#4dd2ff 196|Scruffy Owl|prop|none|#c2b280|#6b705c|#a44a3f|common|#fff1c1 197|Cobalt Condor|twin|none|#ea580c|#111827|#fbbf24|rare|#9d8cff 198|Dusty Windsock|stunt|none|#ddd5c7|#56604a|#f2cc8f|common|#ffb347 199|Patient Owl|biplane|none|#c2b280|#7a6a53|#e9c46a|common|#ffd166 200|Honest Swift|biplane|gnome|#7d8597|#7a6a53|#e9c46a|common|#ffd166 201|Bronze Caracara|twin|none|#ea580c|#fef3c7|#22d3ee|rare|#ff66c4 202|Sunday Quail|stunt|none|#7d8597|#9a8c98|#e9c46a|common|#ffd166 203|Emerald Hobby|twin|none|#15803d|#f8fafc|#f472b6|rare|#9d8cff 204|Thrifty Plover|biplane|none|#8d8d8d|#7a6a53|#e9c46a|common|#ffd166 205|Amber Lancer|seaplane|gnome|#facc15|#f1f5f9|#fb923c|rare|#ff8c1a 206|Jade Albatross|seaplane|none|#0891b2|#1e293b|#fb923c|rare|#ff4d4d 207|Honest Goose|stunt|none|#b08968|#6b705c|#f4f1de|common|#ffd166 208|Second Swift|stunt|none|#7d8597|#5c5c5c|#f2cc8f|common|#ffc971 209|Royal Spitfire|jet|none|#facc15|#0f172a|#22d3ee|rare|#7cff6b 210|Copper Caracara|twin|none|#0891b2|#f1f5f9|#fb923c|rare|#7cff6b 211|Canvas Pony|stunt|none|#aab7b8|#6b705c|#a44a3f|common|#ffc971 212|Lonely Pigeon|stunt|none|#9b7e6b|#6b705c|#e07a5f|common|#ffb347 213|Plasma Banshee|glider|gnome|#450a0a|#134e4a|#f72585|epic|#7df9ff 214|Copper Raven|seaplane|none|#7c3aed|#111827|#ffffff|rare|#ff66c4 215|Bronze Mustang|jet|gnome|#2563eb|#1e293b|#ffffff|rare|#ff66c4 216|Violet Merlin|twin|none|#f97316|#f8fafc|#f472b6|rare|#9d8cff 217|Plasma Herald|delta|gnome|#052e16|#14532d|#ff4d6d|epic|#39ff14 218|Loyal Kettle|biplane|gnome|#b08968|#9a8c98|#c9a227|common|#ffb347 219|Scarlet Gannet|twin|gnome|#c1121f|#0f172a|#000000|rare|#ffe14d 220|Rural Sparrow|stunt|none|#8a9a5b|#9a8c98|#f4f1de|common|#ffe680 221|Muddy Sparrow|stunt|none|#6b705c|#56604a|#e07a5f|common|#ffd166 222|Ivory Hawk|jet|gnome|#1d4ed8|#f1f5f9|#fbbf24|rare|#4dd2ff 223|Thrifty Robin|stunt|none|#aab7b8|#8c7b6b|#e9c46a|common|#ffe680 224|Slow Stork|biplane|none|#8d8d8d|#5c5c5c|#f4f1de|common|#ffb347 225|Sandy Jay|stunt|none|#6b705c|#a3a380|#a44a3f|common|#ffb347 226|Honest Snipe|prop|gnome|#9c8f6e|#5c5c5c|#d08c60|common|#ffb347 227|Phantom Wraith|glider|gnome|#450a0a|#312e81|#ff6a00|epic|#b8ff00 228|Cheap Duck|stunt|none|#6b705c|#5e6472|#f4f1de|common|#ffb347 229|Bronze Condor|seaplane|none|#f97316|#0f172a|#a3e635|rare|#9d8cff 230|Slow Robin|biplane|none|#6b705c|#5c5c5c|#f4f1de|common|#ffb347 231|Quiet Duck|biplane|none|#b5a27a|#a3a380|#f4f1de|common|#ffe680 232|Tangerine Buzzard|twin|none|#ea580c|#0f172a|#f472b6|rare|#9d8cff 233|Bronze Gannet|seaplane|gnome|#be185d|#0f172a|#f472b6|rare|#ff8c1a 234|Violet Lancer|seaplane|gnome|#c1121f|#111827|#ef4444|rare|#7cff6b 235|Electric Corsair|twin|gnome|#7c3aed|#1e293b|#fb923c|rare|#ff8c1a 236|Canvas Owl|biplane|none|#9b7e6b|#a3a380|#3d405b|common|#ffc971 237|Little Starling|biplane|none|#a89f91|#56604a|#f2cc8f|common|#ffd166 238|Foggy Magpie|biplane|none|#c2b280|#5e6472|#bc6c25|common|#fff1c1 239|Sturdy Dove|stunt|gnome|#9b7e6b|#56604a|#f2cc8f|common|#ffb347 240|Chrome Spitfire|seaplane|gnome|#ea580c|#e2e8f0|#ef4444|rare|#4dd2ff 241|Muddy Gull|biplane|none|#8a9a5b|#8c7b6b|#a44a3f|common|#fff1c1 242|Cloudy Stork|biplane|none|#8d8d8d|#5e6472|#588157|common|#ffd166 243|Bronze Lancer|jet|gnome|#f97316|#0f172a|#ffffff|rare|#4dd2ff 244|Amber Viper|jet|gnome|#facc15|#e2e8f0|#f472b6|rare|#7cff6b 245|Scruffy Robin|stunt|none|#b08968|#6b705c|#c9a227|common|#ffe680 246|Last Light|biplane|gnome|#f8f1e5|#d4af37|#b91c1c|legendary|#ff3b3b 247|Tin Kite|prop|none|#b08968|#9a8c98|#588157|common|#fff1c1 248|Teal Falcon|twin|none|#facc15|#fde68a|#ffffff|rare|#ff8c1a 249|Faded Thrush|biplane|none|#c2b280|#4f5d75|#3d405b|common|#fff1c1 250|Brave Bucket|stunt|none|#9c8f6e|#8c7b6b|#bc6c25|common|#ffc971 251|Simple Hangar|prop|none|#b5a27a|#a3a380|#d08c60|common|#ffd166 252|Rusty Gull|stunt|none|#9b7e6b|#4f5d75|#f4f1de|common|#ffb347 253|Sunset Merlin|twin|gnome|#facc15|#111827|#22d3ee|rare|#7cff6b 254|Golden Condor|jet|gnome|#0891b2|#f8fafc|#22d3ee|rare|#ff66c4 255|Foggy Barrel|stunt|none|#b08968|#8c7b6b|#c9a227|common|#fff1c1 256|Lucky Puffin|biplane|none|#9b7e6b|#5e6472|#f2cc8f|common|#ffc971 257|Eclipse Griffin|glider|gnome|#1e1b4b|#7f1d1d|#ffd60a|epic|#c77dff 258|Humble Wren|biplane|gnome|#8a9a5b|#8c7b6b|#f4f1de|common|#ffd166 259|Windy Windsock|prop|none|#7d8597|#a3a380|#f2cc8f|common|#ffb347 260|Lonely Sparrow|prop|gnome|#c2b280|#56604a|#bc6c25|common|#ffb347 261|Shadow Vanguard|glider|gnome|#450a0a|#1e3a8a|#c77dff|epic|#39ff14 262|Cloudy Robin|biplane|gnome|#7d8597|#a3a380|#588157|common|#ffe680 263|Humble Thrush|prop|none|#6b705c|#6f4e37|#a44a3f|common|#ffb347 264|Sunset Corsair|jet|gnome|#15803d|#fde68a|#fb923c|rare|#ffe14d 265|Windy Quail|biplane|none|#7d8597|#4f5d75|#e07a5f|common|#fff1c1 266|Ivory Hobby|twin|gnome|#ea580c|#f1f5f9|#a3e635|rare|#ffe14d 267|Simple Stork|biplane|none|#8d8d8d|#8c7b6b|#d08c60|common|#ffc971 268|Sunday Tarmac|stunt|none|#c2b280|#a3a380|#e9c46a|common|#ffe680 269|Foggy Tarmac|stunt|none|#8d8d8d|#6b705c|#a44a3f|common|#fff1c1 270|Gentle Finch|stunt|none|#9c8f6e|#4f5d75|#e9c46a|common|#ffe680 271|Early Magpie|biplane|none|#c2b280|#4f5d75|#3d405b|common|#ffc971 272|Rainy Owl|prop|gnome|#6b705c|#5e6472|#3d405b|common|#ffc971 273|Slow Pony|stunt|gnome|#b08968|#5c5c5c|#e9c46a|common|#ffd166 274|Quiet Barrel|stunt|none|#9c8f6e|#5e6472|#f2cc8f|common|#ffe680 275|Honest Dove|biplane|none|#9c8f6e|#6f4e37|#c9a227|common|#ffe680 276|Electric Buzzard|seaplane|none|#f97316|#111827|#000000|rare|#ff66c4 277|Storm Valkyrie|glider|gnome|#2e1065|#27272a|#ff4d6d|epic|#ff006e 278|Steady Gull|biplane|none|#aab7b8|#5c5c5c|#e07a5f|common|#ffc971 279|Dusty Plover|stunt|none|#9b7e6b|#6f4e37|#bc6c25|common|#fff1c1 280|Golden Hawk|jet|none|#facc15|#fde68a|#000000|rare|#ff66c4 281|Spotted Jay|biplane|none|#ddd5c7|#9a8c98|#a44a3f|common|#ffc971 282|Honest Kite|stunt|none|#aab7b8|#7a6a53|#c9a227|common|#ffe680 283|Brave Finch|prop|none|#b5a27a|#8c7b6b|#e07a5f|common|#ffc971 284|Golden Corsair|twin|none|#ea580c|#fde68a|#000000|rare|#9d8cff 285|Faded Bucket|prop|gnome|#ddd5c7|#8c7b6b|#d08c60|common|#ffd166 286|Spare Dove|prop|none|#9c8f6e|#7a6a53|#e9c46a|common|#ffc971 287|Silver Peregrine|twin|none|#1d4ed8|#fde68a|#fb923c|rare|#7cff6b 288|Humble Hangar|prop|none|#aab7b8|#9a8c98|#bc6c25|common|#ffb347 289|Azure Corsair|seaplane|none|#f97316|#111827|#000000|rare|#7cff6b 290|Tidy Hangar|stunt|none|#aab7b8|#8c7b6b|#f4f1de|common|#ffc971 291|Early Pigeon|prop|none|#9c8f6e|#5c5c5c|#a44a3f|common|#ffe680 292|Quiet Tern|prop|none|#9b7e6b|#5e6472|#f2cc8f|common|#ffd166 293|Omega Banshee|delta|gnome|#2e1065|#312e81|#4cc9f0|epic|#39ff14 294|Cloudy Teal|prop|none|#aab7b8|#5c5c5c|#a44a3f|common|#ffe680 295|Dusty Pigeon|prop|none|#b08968|#6b705c|#bc6c25|common|#ffb347 296|Patched Tern|biplane|none|#8a9a5b|#4f5d75|#d08c60|common|#ffb347 297|Humble Robin|stunt|none|#ddd5c7|#4f5d75|#a44a3f|common|#ffb347 298|Emerald Lancer|jet|none|#15803d|#0f172a|#a3e635|rare|#ff8c1a 299|Rural Hangar|biplane|gnome|#9b7e6b|#7a6a53|#e9c46a|common|#ffc971 300|Spotted Puffin|stunt|none|#8a9a5b|#56604a|#c9a227|common|#ffe680 301|Brave Crane|prop|none|#c2b280|#8c7b6b|#d08c60|common|#ffb347 302|Bronze Kingfisher|seaplane|none|#0891b2|#f1f5f9|#22d3ee|rare|#7cff6b 303|Neon Spitfire|twin|none|#0891b2|#f1f5f9|#a3e635|rare|#ff8c1a 304|Patient Rook|biplane|none|#c2b280|#6b705c|#588157|common|#fff1c1 305|Little Tern|prop|gnome|#8a9a5b|#5e6472|#a44a3f|common|#ffe680 306|Humble Mule|stunt|none|#9c8f6e|#7a6a53|#a44a3f|common|#ffe680 307|Storm Titan|glider|gnome|#052e16|#7f1d1d|#ff4d6d|epic|#ff9e00 308|Slow Quail|prop|none|#c2b280|#5c5c5c|#a44a3f|common|#ffb347 309|Midnight Wraith|delta|gnome|#450a0a|#1e3a8a|#00f5ff|epic|#7df9ff 310|Humble Tern|prop|none|#a89f91|#a3a380|#3d405b|common|#fff1c1 311|Plain Hangar|stunt|none|#8d8d8d|#6f4e37|#588157|common|#ffe680 312|Simple Starling|prop|none|#7d8597|#7a6a53|#f2cc8f|common|#ffc971 313|Indigo Albatross|twin|gnome|#be185d|#fef3c7|#a3e635|rare|#ff66c4 314|Loyal Mallard|stunt|none|#aab7b8|#a3a380|#d08c60|common|#ffb347 315|Aurora Phoenix|delta|gnome|#2e1065|#581c87|#ff4d6d|epic|#c77dff 316|Sandy Crane|prop|none|#8d8d8d|#a3a380|#e9c46a|common|#ffb347 317|Onyx Hawk|jet|none|#f97316|#f1f5f9|#a3e635|rare|#ffe14d 318|Thunder Griffin|glider|gnome|#3b0764|#7f1d1d|#4cc9f0|epic|#b8ff00 319|Nova Herald|delta|gnome|#052e16|#1e293b|#00f5ff|epic|#7df9ff 320|Emerald Kestrel|seaplane|gnome|#15803d|#1e293b|#ffffff|rare|#ffe14d 321|Steady Finch|prop|gnome|#c2b280|#56604a|#588157|common|#fff1c1 322|Ivory Caracara|twin|gnome|#7c3aed|#fef3c7|#fbbf24|rare|#7cff6b 323|Simple Pelican|biplane|gnome|#9b7e6b|#9a8c98|#f4f1de|common|#ffc971 324|Rusty Stork|biplane|none|#9b7e6b|#6b705c|#f4f1de|common|#fff1c1 325|Teal Eagle|seaplane|none|#1d4ed8|#e2e8f0|#000000|rare|#4dd2ff 326|Sandy Dove|prop|gnome|#8a9a5b|#8c7b6b|#f4f1de|common|#ffb347 327|Coral Raven|twin|gnome|#0891b2|#f8fafc|#000000|rare|#9d8cff 328|Muddy Mallard|prop|none|#c2b280|#5e6472|#588157|common|#fff1c1 329|Lonely Stork|prop|none|#7d8597|#9a8c98|#588157|common|#ffe680 330|Patched Kite|biplane|gnome|#8a9a5b|#9a8c98|#f2cc8f|common|#fff1c1 331|Scruffy Puffin|biplane|gnome|#ddd5c7|#56604a|#588157|common|#ffc971 332|Nova Valkyrie|glider|gnome|#1e1b4b|#1e293b|#f72585|epic|#b8ff00 333|Sturdy Lantern|biplane|gnome|#8a9a5b|#4f5d75|#d08c60|common|#ffe680 334|Simple Windsock|stunt|gnome|#b08968|#6b705c|#bc6c25|common|#ffc971 335|Simple Tern|biplane|gnome|#aab7b8|#56604a|#bc6c25|common|#ffe680 336|Early Lantern|prop|none|#7d8597|#5c5c5c|#e07a5f|common|#ffb347 337|Sunday Mule|stunt|none|#a89f91|#a3a380|#a44a3f|common|#ffd166 338|Sunday Crow|prop|none|#ddd5c7|#a3a380|#3d405b|common|#ffb347 339|Foggy Snipe|stunt|none|#9c8f6e|#4f5d75|#f2cc8f|common|#ffb347 340|Little Bucket|stunt|none|#8a9a5b|#4f5d75|#f4f1de|common|#ffc971 341|Electric Mustang|seaplane|none|#15803d|#f1f5f9|#fbbf24|rare|#9d8cff 342|Weary Magpie|biplane|none|#9c8f6e|#a3a380|#588157|common|#ffd166 343|Honest Windsock|prop|none|#8a9a5b|#8c7b6b|#e9c46a|common|#ffc971 344|Dusty Barrel|biplane|none|#6b705c|#56604a|#d08c60|common|#ffb347 345|Tin Lantern|stunt|none|#8a9a5b|#9a8c98|#f4f1de|common|#fff1c1 346|Royal Albatross|twin|gnome|#be185d|#e2e8f0|#ef4444|rare|#9d8cff 347|Foggy Thrush|biplane|none|#9c8f6e|#8c7b6b|#f4f1de|common|#ffb347 348|Sandy Rook|prop|none|#6b705c|#a3a380|#d08c60|common|#ffd166 349|Second Owl|stunt|none|#6b705c|#7a6a53|#c9a227|common|#ffb347 350|Lucky Mallard|prop|none|#8d8d8d|#6f4e37|#f4f1de|common|#ffb347 351|Storm Banshee|delta|gnome|#4a0404|#7f1d1d|#c77dff|epic|#ff006e 352|Gentle Sparrow|stunt|none|#7d8597|#5e6472|#f2cc8f|common|#ffe680 353|Sunset Cormorant|twin|gnome|#facc15|#1e293b|#ffffff|rare|#ff66c4 354|Loyal Tern|stunt|none|#ddd5c7|#a3a380|#a44a3f|common|#ffd166 355|Sturdy Tern|stunt|none|#8d8d8d|#6b705c|#d08c60|common|#ffc971 356|Violet Buzzard|seaplane|none|#15803d|#f8fafc|#a3e635|rare|#ffe14d 357|Honest Pony|biplane|none|#6b705c|#6f4e37|#e07a5f|common|#ffe680 358|Rural Magpie|stunt|none|#9b7e6b|#5c5c5c|#e07a5f|common|#ffb347 359|Weary Wagon|prop|none|#b5a27a|#4f5d75|#3d405b|common|#fff1c1 360|Lonely Magpie|stunt|none|#7d8597|#9a8c98|#c9a227|common|#ffd166 361|Windy Kite|biplane|gnome|#8a9a5b|#5e6472|#e9c46a|common|#ffb347 362|Quiet Thrush|biplane|none|#7d8597|#8c7b6b|#e9c46a|common|#ffb347 363|Lucky Gull|biplane|none|#ddd5c7|#6b705c|#f2cc8f|common|#ffc971 364|Bronze Shrike|seaplane|gnome|#2563eb|#f1f5f9|#22d3ee|rare|#7cff6b 365|Specter Oracle|delta|gnome|#0b1020|#14532d|#f72585|epic|#39ff14 366|Sleepy Pelican|stunt|none|#6b705c|#8c7b6b|#bc6c25|common|#ffd166 367|Dusty Quail|stunt|none|#9c8f6e|#6f4e37|#588157|common|#ffd166 368|Omega Oracle|glider|gnome|#3b0764|#1e293b|#39ff14|epic|#7df9ff 369|Windy Kettle|prop|none|#b08968|#8c7b6b|#d08c60|common|#ffb347 370|Jade Raven|jet|gnome|#1d4ed8|#fde68a|#000000|rare|#4dd2ff 371|Loyal Heron|prop|gnome|#6b705c|#5c5c5c|#bc6c25|common|#ffd166 372|Dusty Pelican|stunt|none|#c2b280|#8c7b6b|#e07a5f|common|#ffc971 373|Gentle Windsock|prop|none|#7d8597|#7a6a53|#3d405b|common|#fff1c1 374|Ruby Falcon|jet|gnome|#facc15|#f8fafc|#f472b6|rare|#ffe14d 375|Indigo Merlin|jet|gnome|#1d4ed8|#f8fafc|#22d3ee|rare|#4dd2ff 376|Aurora Monarch|delta|gnome|#042f2e|#14532d|#ff6a00|epic|#7df9ff 377|Ember Herald|glider|gnome|#2e1065|#581c87|#ff6a00|epic|#39ff14 378|Specter Herald|delta|gnome|#172554|#27272a|#c77dff|epic|#b8ff00 379|Spotted Rook|prop|none|#b08968|#5c5c5c|#e9c46a|common|#ffe680 380|Ruby Osprey|seaplane|gnome|#be185d|#e2e8f0|#fb923c|rare|#9d8cff 381|Lucky Plover|biplane|none|#b5a27a|#8c7b6b|#588157|common|#ffc971 382|Steady Kettle|stunt|none|#a89f91|#6f4e37|#3d405b|common|#ffe680 383|Sunday Goose|prop|none|#b5a27a|#56604a|#bc6c25|common|#ffb347 384|Simple Mule|stunt|none|#c2b280|#7a6a53|#3d405b|common|#ffe680 385|Spotted Pigeon|prop|none|#8d8d8d|#6b705c|#588157|common|#ffb347 386|Muddy Swift|stunt|none|#6b705c|#4f5d75|#f4f1de|common|#ffb347 387|Sturdy Goose|prop|gnome|#b5a27a|#a3a380|#e07a5f|common|#ffe680 388|Plain Barrel|prop|none|#9c8f6e|#56604a|#d08c60|common|#ffc971 389|Emerald Hawk|twin|none|#facc15|#f1f5f9|#fb923c|rare|#ff66c4 390|Steady Tarmac|stunt|none|#b08968|#8c7b6b|#bc6c25|common|#ffb347 391|Tangerine Gannet|seaplane|none|#1d4ed8|#f1f5f9|#22d3ee|rare|#ff4d4d 392|Sunday Windsock|biplane|none|#9b7e6b|#4f5d75|#a44a3f|common|#ffe680 393|Neon Albatross|seaplane|none|#c1121f|#fef3c7|#22d3ee|rare|#ffe14d 394|Sunday Thrush|stunt|none|#c2b280|#5c5c5c|#bc6c25|common|#ffd166 395|Sturdy Heron|prop|none|#7d8597|#6b705c|#e07a5f|common|#ffd166 396|Rainy Hangar|stunt|gnome|#9b7e6b|#7a6a53|#f4f1de|common|#ffe680 397|Silver Viper|seaplane|gnome|#7c3aed|#111827|#22d3ee|rare|#ff8c1a 398|Tin Thrush|stunt|none|#8d8d8d|#4f5d75|#bc6c25|common|#ffc971 399|Canvas Puffin|prop|none|#7d8597|#4f5d75|#3d405b|common|#ffb347 400|Simple Kite|prop|none|#b5a27a|#5e6472|#d08c60|common|#ffd166 401|Tidy Lark|stunt|none|#b08968|#56604a|#c9a227|common|#ffe680 402|Sandy Sparrow|stunt|none|#6b705c|#5c5c5c|#e9c46a|common|#ffd166 403|Coral Kingfisher|twin|none|#15803d|#fef3c7|#f472b6|rare|#ff8c1a 404|Crimson Vulture|twin|none|#be185d|#111827|#22d3ee|rare|#4dd2ff 405|Grey Kettle|biplane|none|#b08968|#6b705c|#588157|common|#ffe680 406|Lonely Jay|stunt|none|#8a9a5b|#56604a|#c9a227|common|#ffb347 407|Humble Magpie|stunt|none|#8d8d8d|#6b705c|#c9a227|common|#ffd166 408|Rainy Sparrow|prop|none|#b08968|#56604a|#e07a5f|common|#fff1c1 409|Cobalt Albatross|twin|gnome|#0891b2|#fde68a|#f472b6|rare|#ffe14d 410|Rusty Robin|prop|none|#b5a27a|#8c7b6b|#d08c60|common|#fff1c1 411|Second Teal|prop|none|#a89f91|#6f4e37|#f4f1de|common|#fff1c1 412|Royal Harrier|jet|none|#ea580c|#f8fafc|#000000|rare|#7cff6b 413|Faded Lantern|prop|none|#8a9a5b|#8c7b6b|#3d405b|common|#ffc971 414|Little Windsock|biplane|none|#7d8597|#6f4e37|#e9c46a|common|#ffe680 415|Patched Magpie|stunt|gnome|#8a9a5b|#5c5c5c|#a44a3f|common|#ffe680 416|Sturdy Teal|biplane|none|#b08968|#7a6a53|#c9a227|common|#ffe680 417|Grey Tarmac|stunt|none|#6b705c|#4f5d75|#e9c46a|common|#ffc971 418|Gentle Quail|stunt|none|#b08968|#a3a380|#c9a227|common|#ffd166 419|Tin Kettle|stunt|none|#8d8d8d|#5c5c5c|#e07a5f|common|#ffb347 420|Ember Valkyrie|delta|gnome|#0b1020|#7f1d1d|#ffd60a|epic|#c77dff 421|Neon Caracara|jet|gnome|#0891b2|#fde68a|#f472b6|rare|#ff66c4 422|Steady Swift|biplane|none|#7d8597|#8c7b6b|#f2cc8f|common|#ffe680 423|Azure Vulture|seaplane|none|#facc15|#e2e8f0|#22d3ee|rare|#ff4d4d 424|Scarlet Condor|jet|none|#c1121f|#f8fafc|#f472b6|rare|#ff4d4d 425|Void Herald|delta|gnome|#4a0404|#1e3a8a|#ff6a00|epic|#f72585 426|Rusty Rook|stunt|gnome|#b5a27a|#8c7b6b|#bc6c25|common|#ffd166 427|Spare Thrush|stunt|none|#b5a27a|#a3a380|#a44a3f|common|#fff1c1 428|Scruffy Teal|biplane|none|#7d8597|#5e6472|#e07a5f|common|#ffc971 429|Sleepy Sparrow|biplane|none|#a89f91|#9a8c98|#588157|common|#ffb347 430|Dusty Puffin|prop|none|#a89f91|#5e6472|#3d405b|common|#ffb347 431|Dusty Goose|biplane|none|#7d8597|#a3a380|#f2cc8f|common|#ffd166 432|Cheap Teal|prop|none|#b08968|#56604a|#588157|common|#ffd166 433|Onyx Albatross|seaplane|gnome|#15803d|#e2e8f0|#ffffff|rare|#4dd2ff 434|Cheap Magpie|stunt|none|#aab7b8|#6f4e37|#bc6c25|common|#ffe680 435|Violet Kestrel|twin|none|#0891b2|#fde68a|#fbbf24|rare|#ffe14d 436|Loyal Mule|stunt|gnome|#ddd5c7|#4f5d75|#a44a3f|common|#ffd166 437|Silver Shrike|seaplane|none|#ea580c|#f1f5f9|#fbbf24|rare|#ff8c1a 438|Cloudy Goose|biplane|none|#a89f91|#7a6a53|#3d405b|common|#fff1c1 439|Spare Puffin|biplane|none|#b08968|#6f4e37|#3d405b|common|#ffd166 440|Thrifty Wren|prop|none|#7d8597|#6b705c|#f2cc8f|common|#fff1c1 441|Slow Hangar|prop|gnome|#8d8d8d|#5e6472|#3d405b|common|#ffb347 442|Simple Tarmac|stunt|gnome|#7d8597|#a3a380|#f2cc8f|common|#ffb347 443|Bronze Buzzard|twin|gnome|#2563eb|#f8fafc|#ef4444|rare|#7cff6b 444|Cloudy Thrush|biplane|none|#9b7e6b|#5e6472|#c9a227|common|#ffb347 445|Crimson Caracara|twin|gnome|#1d4ed8|#1e293b|#fb923c|rare|#7cff6b 446|Quiet Goose|stunt|none|#ddd5c7|#7a6a53|#d08c60|common|#ffe680 447|Dusty Owl|stunt|none|#8a9a5b|#5c5c5c|#e07a5f|common|#ffc971 448|Storm Reaper|delta|gnome|#2e1065|#581c87|#39ff14|epic|#c77dff 449|Gentle Teal|prop|none|#8d8d8d|#9a8c98|#f4f1de|common|#ffe680 450|Golden Buzzard|seaplane|none|#be185d|#f1f5f9|#f472b6|rare|#4dd2ff 451|Little Snipe|stunt|gnome|#9c8f6e|#9a8c98|#3d405b|common|#ffd166 452|Tin Robin|prop|none|#c2b280|#a3a380|#c9a227|common|#ffe680 453|Teal Osprey|twin|gnome|#7c3aed|#f1f5f9|#22d3ee|rare|#7cff6b 454|Chrome Osprey|jet|gnome|#f97316|#0f172a|#f472b6|rare|#7cff6b 455|Weary Gull|biplane|none|#ddd5c7|#9a8c98|#a44a3f|common|#ffe680 456|Slow Sparrow|biplane|gnome|#b08968|#5e6472|#e9c46a|common|#fff1c1 457|Tin Teal|stunt|none|#c2b280|#8c7b6b|#e9c46a|common|#ffb347 458|Spotted Crane|stunt|none|#b08968|#56604a|#f4f1de|common|#ffd166 459|Storm Warden|glider|gnome|#0b1020|#312e81|#ff4d6d|epic|#ff006e 460|Dead Reckoning|twin|none|#1f2937|#111827|#f0fdf4|legendary|#a7f3d0 461|Patient Wagon|biplane|gnome|#b08968|#8c7b6b|#e07a5f|common|#ffc971 462|Cloudy Wagon|stunt|none|#9c8f6e|#a3a380|#c9a227|common|#ffc971 463|Tidy Lantern|prop|none|#a89f91|#6b705c|#e07a5f|common|#ffb347 464|Phantom Banshee|delta|gnome|#450a0a|#1e3a8a|#39ff14|epic|#c77dff 465|Cheap Snipe|biplane|none|#7d8597|#8c7b6b|#c9a227|common|#ffc971 466|Muddy Pony|prop|none|#b5a27a|#9a8c98|#e9c46a|common|#ffc971 467|Emerald Falcon|twin|gnome|#2563eb|#fef3c7|#000000|rare|#9d8cff 468|Tin Gull|stunt|none|#9b7e6b|#7a6a53|#a44a3f|common|#ffd166 469|Sandy Crow|prop|none|#aab7b8|#5e6472|#f4f1de|common|#fff1c1 470|Sturdy Rook|stunt|none|#9b7e6b|#4f5d75|#e07a5f|common|#ffe680 471|Patient Teal|stunt|gnome|#c2b280|#a3a380|#e9c46a|common|#ffc971 472|Ember Vanguard|glider|gnome|#1e1b4b|#134e4a|#c77dff|epic|#ff006e 473|Cobalt Raven|seaplane|none|#15803d|#f1f5f9|#ffffff|rare|#ff66c4 474|Teal Shrike|jet|gnome|#0891b2|#f1f5f9|#f472b6|rare|#9d8cff 475|Chrome Kingfisher|twin|none|#7c3aed|#f1f5f9|#22d3ee|rare|#9d8cff 476|Bronze Hawk|seaplane|none|#15803d|#0f172a|#22d3ee|rare|#ff8c1a 477|Tangerine Merlin|twin|none|#7c3aed|#fef3c7|#22d3ee|rare|#ff66c4 478|Slow Pigeon|prop|none|#c2b280|#5e6472|#f4f1de|common|#ffd166 479|Windy Snipe|prop|none|#9c8f6e|#8c7b6b|#588157|common|#ffe680 480|Violet Osprey|seaplane|gnome|#7c3aed|#fef3c7|#f472b6|rare|#ff8c1a 481|Canvas Tern|biplane|none|#8a9a5b|#a3a380|#d08c60|common|#fff1c1 482|Cheap Plover|stunt|none|#a89f91|#5e6472|#588157|common|#ffe680 483|Rusty Teal|biplane|none|#b5a27a|#a3a380|#a44a3f|common|#ffb347 484|Scruffy Rook|stunt|none|#a89f91|#4f5d75|#a44a3f|common|#ffe680 485|Second Goose|prop|none|#c2b280|#6b705c|#e9c46a|common|#ffc971 486|Cheap Pelican|biplane|gnome|#9b7e6b|#6f4e37|#f4f1de|common|#ffd166 487|Onyx Harrier|jet|gnome|#0891b2|#f8fafc|#f472b6|rare|#7cff6b 488|Ruby Raven|seaplane|none|#2563eb|#f1f5f9|#a3e635|rare|#4dd2ff 489|Lucky Magpie|prop|none|#9c8f6e|#5e6472|#bc6c25|common|#ffd166 490|Nova Tempest|glider|gnome|#1e1b4b|#7f1d1d|#00f5ff|epic|#7df9ff 491|Golden Hobby|jet|none|#c1121f|#fde68a|#22d3ee|rare|#ffe14d 492|Canvas Wagon|biplane|none|#ddd5c7|#a3a380|#3d405b|common|#ffb347 493|Plain Lantern|biplane|none|#9c8f6e|#56604a|#d08c60|common|#ffc971 494|Weary Pelican|prop|none|#8d8d8d|#5e6472|#f4f1de|common|#ffe680 495|Spare Teal|biplane|none|#8d8d8d|#7a6a53|#588157|common|#ffe680 496|Rainy Windsock|biplane|none|#9b7e6b|#8c7b6b|#e9c46a|common|#ffe680 497|Tangerine Raven|twin|none|#15803d|#111827|#000000|rare|#4dd2ff 498|Sturdy Sparrow|biplane|none|#9c8f6e|#56604a|#3d405b|common|#ffb347 499|Copper Condor|jet|gnome|#facc15|#0f172a|#22d3ee|rare|#4dd2ff 500|Gentle Kettle|stunt|none|#b5a27a|#5e6472|#588157|common|#ffd166 501|Azure Lancer|jet|none|#c1121f|#fde68a|#fb923c|rare|#7cff6b 502|Lonely Teal|prop|gnome|#8d8d8d|#5e6472|#c9a227|common|#ffd166 503|Cobalt Osprey|seaplane|gnome|#7c3aed|#0f172a|#fbbf24|rare|#4dd2ff 504|Rural Teal|stunt|gnome|#7d8597|#7a6a53|#bc6c25|common|#fff1c1 505|Cloudy Kettle|prop|none|#9b7e6b|#6f4e37|#c9a227|common|#ffe680 506|Rural Swift|stunt|none|#b5a27a|#56604a|#d08c60|common|#ffe680 507|Sunset Spitfire|jet|gnome|#7c3aed|#f8fafc|#ffffff|rare|#4dd2ff 508|Nova Saint|glider|gnome|#2e1065|#14532d|#39ff14|epic|#39ff14 509|Muddy Snipe|prop|none|#9b7e6b|#7a6a53|#f2cc8f|common|#ffc971 510|Electric Eagle|jet|gnome|#be185d|#fde68a|#f472b6|rare|#9d8cff 511|Golden Osprey|twin|gnome|#be185d|#fde68a|#fbbf24|rare|#ff4d4d 512|Loyal Goose|stunt|none|#6b705c|#a3a380|#c9a227|common|#ffe680 513|Plain Bucket|stunt|none|#b08968|#5c5c5c|#f4f1de|common|#ffe680 514|Early Owl|biplane|none|#b08968|#a3a380|#d08c60|common|#fff1c1 515|Midnight Sentinel|delta|gnome|#052e16|#312e81|#ff4d6d|epic|#00f5ff 516|Simple Pigeon|stunt|none|#c2b280|#6b705c|#588157|common|#fff1c1 517|Weary Puffin|biplane|none|#aab7b8|#4f5d75|#d08c60|common|#ffc971 518|Onyx Caracara|seaplane|none|#facc15|#e2e8f0|#ffffff|rare|#9d8cff 519|Cheap Wagon|prop|none|#c2b280|#a3a380|#d08c60|common|#ffb347 520|Ivory Osprey|twin|none|#facc15|#e2e8f0|#fbbf24|rare|#7cff6b 521|Spare Mallard|prop|none|#b5a27a|#5e6472|#d08c60|common|#ffe680 522|Thrifty Lark|prop|none|#7d8597|#5e6472|#bc6c25|common|#fff1c1 523|Azure Kestrel|twin|gnome|#7c3aed|#fde68a|#ef4444|rare|#ff4d4d 524|Scruffy Lark|prop|gnome|#aab7b8|#8c7b6b|#e9c46a|common|#ffe680 525|Ivory Condor|seaplane|none|#ea580c|#f8fafc|#ef4444|rare|#7cff6b 526|Cobalt Mustang|twin|gnome|#7c3aed|#e2e8f0|#f472b6|rare|#ff4d4d 527|Slow Rook|biplane|none|#c2b280|#9a8c98|#d08c60|common|#ffd166 528|Sandy Wren|biplane|none|#c2b280|#8c7b6b|#588157|common|#fff1c1 529|Sturdy Crane|biplane|none|#c2b280|#8c7b6b|#d08c60|common|#ffd166 530|Scruffy Tarmac|stunt|none|#7d8597|#5c5c5c|#f2cc8f|common|#ffd166 531|Cloudy Crane|biplane|none|#7d8597|#a3a380|#a44a3f|common|#ffb347 532|Quiet Crow|prop|none|#c2b280|#4f5d75|#e07a5f|common|#ffd166 533|Onyx Raven|jet|none|#facc15|#e2e8f0|#22d3ee|rare|#4dd2ff 534|Frost Valkyrie|delta|gnome|#172554|#1e293b|#f72585|epic|#00f5ff 535|Windy Pigeon|stunt|none|#9b7e6b|#56604a|#588157|common|#ffc971 536|Coral Lancer|jet|gnome|#15803d|#fef3c7|#fbbf24|rare|#9d8cff 537|Humble Heron|stunt|gnome|#7d8597|#56604a|#bc6c25|common|#ffe680 538|Amber Albatross|seaplane|none|#c1121f|#f8fafc|#a3e635|rare|#ffe14d 539|Cloudy Rook|prop|none|#8d8d8d|#a3a380|#a44a3f|common|#ffb347 540|Coral Osprey|seaplane|none|#ea580c|#fef3c7|#000000|rare|#9d8cff 541|Neon Viper|seaplane|gnome|#1d4ed8|#fef3c7|#fb923c|rare|#ff66c4 542|Violet Condor|seaplane|gnome|#7c3aed|#f1f5f9|#f472b6|rare|#7cff6b 543|Plasma Phoenix|glider|gnome|#042f2e|#581c87|#ffd60a|epic|#c77dff 544|Rainy Goose|prop|none|#8d8d8d|#4f5d75|#e07a5f|common|#fff1c1 545|Royal Merlin|seaplane|gnome|#be185d|#0f172a|#f472b6|rare|#ff4d4d 546|Early Gull|biplane|none|#8d8d8d|#5e6472|#588157|common|#ffd166 547|Onyx Vulture|twin|gnome|#0891b2|#fef3c7|#ffffff|rare|#ff8c1a 548|Plain Jay|stunt|none|#b08968|#5e6472|#3d405b|common|#fff1c1 549|Canvas Mule|biplane|none|#9c8f6e|#7a6a53|#e9c46a|common|#ffb347 550|Neon Shrike|seaplane|none|#15803d|#e2e8f0|#ffffff|rare|#ff4d4d 551|Dusty Sparrow|stunt|none|#8a9a5b|#5c5c5c|#a44a3f|common|#ffc971 552|Lucky Hangar|biplane|none|#8a9a5b|#5e6472|#f2cc8f|common|#ffe680 553|Sandy Quail|biplane|none|#9c8f6e|#5c5c5c|#bc6c25|common|#ffd166 554|Weary Duck|biplane|none|#7d8597|#5c5c5c|#3d405b|common|#ffd166 555|Cobalt Harrier|jet|none|#f97316|#fde68a|#22d3ee|rare|#ffe14d 556|Muddy Rook|prop|none|#8a9a5b|#4f5d75|#a44a3f|common|#ffd166 557|Patched Lantern|stunt|gnome|#9b7e6b|#4f5d75|#bc6c25|common|#ffb347 558|Jade Harrier|seaplane|none|#ea580c|#111827|#f472b6|rare|#ff8c1a 559|Royal Hobby|seaplane|none|#0891b2|#fde68a|#ffffff|rare|#4dd2ff 560|Coral Gannet|jet|gnome|#2563eb|#111827|#ffffff|rare|#ff66c4 561|Spotted Wagon|biplane|gnome|#b5a27a|#5e6472|#a44a3f|common|#ffd166 562|Sleepy Goose|stunt|none|#8a9a5b|#5e6472|#588157|common|#ffb347 563|Lucky Crane|stunt|gnome|#a89f91|#5c5c5c|#e07a5f|common|#fff1c1 564|Rusty Owl|stunt|gnome|#8a9a5b|#6f4e37|#f2cc8f|common|#ffe680 565|Slow Wagon|prop|none|#7d8597|#9a8c98|#3d405b|common|#ffc971 566|Humble Rook|biplane|none|#b08968|#7a6a53|#3d405b|common|#ffd166 567|Dusty Mule|prop|gnome|#9c8f6e|#9a8c98|#c9a227|common|#fff1c1 568|Windy Dove|prop|none|#8d8d8d|#4f5d75|#f2cc8f|common|#ffc971 569|Thrifty Sparrow|prop|gnome|#7d8597|#9a8c98|#f2cc8f|common|#fff1c1 570|Foggy Gull|prop|none|#6b705c|#a3a380|#f2cc8f|common|#ffd166 571|Sleepy Thrush|biplane|gnome|#7d8597|#56604a|#f4f1de|common|#ffc971 572|Faded Duck|biplane|none|#b5a27a|#7a6a53|#e9c46a|common|#fff1c1 573|Humble Dove|prop|none|#c2b280|#5e6472|#a44a3f|common|#fff1c1 574|Faded Quail|biplane|gnome|#8a9a5b|#5e6472|#e9c46a|common|#ffb347 575|Loyal Magpie|biplane|gnome|#8a9a5b|#4f5d75|#e9c46a|common|#ffc971 576|Tangerine Vulture|seaplane|none|#f97316|#1e293b|#fbbf24|rare|#ffe14d 577|Humble Sparrow|stunt|gnome|#a89f91|#6b705c|#3d405b|common|#ffb347 578|Sunday Dove|biplane|gnome|#7d8597|#56604a|#e9c46a|common|#ffd166 579|Sandy Plover|biplane|gnome|#b08968|#7a6a53|#f4f1de|common|#fff1c1 580|Little Sparrow|stunt|gnome|#c2b280|#6b705c|#3d405b|common|#ffc971 581|Tidy Teal|prop|none|#6b705c|#5e6472|#d08c60|common|#ffc971 582|Lonely Tarmac|stunt|none|#9c8f6e|#56604a|#f4f1de|common|#ffc971 583|Cheap Puffin|prop|gnome|#aab7b8|#8c7b6b|#3d405b|common|#ffe680 584|Loyal Bucket|prop|none|#a89f91|#9a8c98|#f2cc8f|common|#ffd166 585|Steady Robin|biplane|none|#8a9a5b|#8c7b6b|#f2cc8f|common|#ffc971 586|Tin Bucket|biplane|none|#8d8d8d|#56604a|#bc6c25|common|#ffe680 587|Golden Peregrine|seaplane|gnome|#ea580c|#0f172a|#fb923c|rare|#4dd2ff 588|Grey Thrush|stunt|none|#7d8597|#5e6472|#e9c46a|common|#fff1c1 589|Lonely Wagon|prop|none|#aab7b8|#6b705c|#3d405b|common|#ffe680 590|Patched Robin|prop|none|#9c8f6e|#7a6a53|#3d405b|common|#fff1c1 591|Sunset Vulture|seaplane|none|#0891b2|#1e293b|#ffffff|rare|#9d8cff 592|Crimson Shrike|twin|none|#0891b2|#111827|#22d3ee|rare|#ff8c1a 593|Cloudy Plover|prop|gnome|#aab7b8|#6f4e37|#f2cc8f|common|#ffe680 594|Silver Mustang|seaplane|none|#f97316|#111827|#000000|rare|#ff4d4d 595|Chrome Hawk|jet|gnome|#2563eb|#1e293b|#000000|rare|#9d8cff 596|Lucky Bucket|stunt|gnome|#9c8f6e|#5e6472|#d08c60|common|#ffc971 597|Coral Condor|seaplane|none|#ea580c|#e2e8f0|#ef4444|rare|#9d8cff 598|Early Dove|prop|none|#8d8d8d|#4f5d75|#e07a5f|common|#ffb347 599|Windy Duck|biplane|none|#7d8597|#6b705c|#e07a5f|common|#ffc971 600|Humble Windsock|biplane|gnome|#8d8d8d|#56604a|#e9c46a|common|#ffb347 601|Tangerine Goshawk|twin|gnome|#7c3aed|#fde68a|#f472b6|rare|#ffe14d 602|Muddy Heron|prop|none|#9c8f6e|#6f4e37|#bc6c25|common|#ffe680 603|Weary Hangar|biplane|none|#c2b280|#6f4e37|#bc6c25|common|#ffd166 604|Scruffy Tern|prop|none|#a89f91|#5c5c5c|#3d405b|common|#ffd166 605|Emerald Gannet|jet|none|#be185d|#0f172a|#fb923c|rare|#ff8c1a 606|Midnight Vanguard|delta|gnome|#450a0a|#1e3a8a|#ffd60a|epic|#ff9e00 607|Sleepy Puffin|biplane|none|#9c8f6e|#8c7b6b|#e07a5f|common|#ffe680 608|Windy Magpie|prop|none|#b5a27a|#8c7b6b|#588157|common|#ffe680 609|Ivory Viper|twin|gnome|#f97316|#1e293b|#ef4444|rare|#4dd2ff 610|Gentle Plover|prop|gnome|#6b705c|#a3a380|#e07a5f|common|#ffe680 611|Royal Hawk|jet|none|#7c3aed|#111827|#fb923c|rare|#ffe14d 612|Royal Buzzard|jet|none|#facc15|#1e293b|#fbbf24|rare|#ff4d4d 613|Brave Sparrow|stunt|none|#6b705c|#7a6a53|#a44a3f|common|#ffe680 614|Phantom Sentinel|delta|gnome|#1e1b4b|#7f1d1d|#ff4d6d|epic|#ff9e00 615|Plain Wren|biplane|none|#7d8597|#56604a|#d08c60|common|#ffb347 616|Patched Starling|prop|none|#a89f91|#4f5d75|#588157|common|#ffe680 617|Lucky Owl|stunt|none|#c2b280|#6b705c|#c9a227|common|#ffb347 618|Seven Seven Seven|jet|gnome|#0a0a0a|#1c1c1c|#ffd700|legendary|#ffd700 619|Humble Duck|biplane|none|#b5a27a|#9a8c98|#d08c60|common|#ffe680 620|Windy Crane|prop|none|#c2b280|#5c5c5c|#a44a3f|common|#ffc971 621|Jade Gannet|jet|none|#facc15|#fef3c7|#ffffff|rare|#7cff6b 622|Grey Wren|biplane|none|#7d8597|#6f4e37|#e9c46a|common|#ffd166 623|Sleepy Rook|stunt|none|#9c8f6e|#56604a|#f2cc8f|common|#ffd166 624|Ivory Harrier|twin|none|#f97316|#fde68a|#22d3ee|rare|#7cff6b 625|Neon Gannet|seaplane|gnome|#c1121f|#1e293b|#ffffff|rare|#ff66c4 626|Copper Viper|seaplane|none|#1d4ed8|#f1f5f9|#fbbf24|rare|#ffe14d 627|Cheap Kite|prop|none|#c2b280|#5e6472|#3d405b|common|#ffb347 628|Nova Sentinel|delta|gnome|#042f2e|#1e293b|#39ff14|epic|#b8ff00 629|Weary Kettle|prop|gnome|#aab7b8|#6b705c|#e07a5f|common|#fff1c1 630|Steady Quail|prop|gnome|#7d8597|#56604a|#f4f1de|common|#fff1c1 631|Shadow Tempest|glider|gnome|#052e16|#581c87|#4cc9f0|epic|#c77dff 632|Foggy Puffin|prop|none|#b5a27a|#4f5d75|#f4f1de|common|#fff1c1 633|Sunset Caracara|jet|gnome|#15803d|#f8fafc|#f472b6|rare|#ff66c4 634|Slow Mallard|stunt|none|#b08968|#56604a|#3d405b|common|#fff1c1 635|Grey Bucket|stunt|none|#aab7b8|#5e6472|#bc6c25|common|#fff1c1 636|Humble Starling|stunt|none|#c2b280|#9a8c98|#bc6c25|common|#ffe680 637|Gentle Robin|biplane|none|#b5a27a|#56604a|#f2cc8f|common|#fff1c1 638|Muddy Wagon|prop|none|#9c8f6e|#5e6472|#588157|common|#fff1c1 639|Grey Pigeon|biplane|none|#ddd5c7|#56604a|#f4f1de|common|#ffb347 640|Tidy Goose|prop|none|#8d8d8d|#6f4e37|#f2cc8f|common|#ffc971 641|Scarlet Lancer|seaplane|none|#15803d|#f1f5f9|#ef4444|rare|#ff4d4d 642|Scarlet Harrier|seaplane|gnome|#c1121f|#fde68a|#22d3ee|rare|#ffe14d 643|Humble Jay|biplane|none|#6b705c|#5e6472|#588157|common|#ffd166 644|Brave Pony|stunt|none|#b08968|#8c7b6b|#3d405b|common|#fff1c1 645|Loyal Kite|biplane|none|#7d8597|#8c7b6b|#f2cc8f|common|#ffd166 646|Patient Duck|biplane|none|#9c8f6e|#5c5c5c|#e07a5f|common|#ffd166 647|Tidy Jay|stunt|none|#9c8f6e|#4f5d75|#bc6c25|common|#ffb347 648|Early Mallard|prop|none|#9c8f6e|#6b705c|#3d405b|common|#ffc971 649|Tin Finch|prop|none|#8a9a5b|#5e6472|#3d405b|common|#ffc971 650|Golden Lancer|twin|none|#7c3aed|#fef3c7|#fb923c|rare|#ff4d4d 651|Rusty Kettle|stunt|none|#6b705c|#5c5c5c|#f2cc8f|common|#ffd166 652|Quiet Wagon|prop|none|#aab7b8|#4f5d75|#e07a5f|common|#fff1c1 653|Quiet Windsock|biplane|gnome|#aab7b8|#6f4e37|#e9c46a|common|#ffe680 654|Spotted Lantern|stunt|gnome|#ddd5c7|#7a6a53|#c9a227|common|#ffd166 655|Steady Duck|stunt|none|#a89f91|#9a8c98|#f2cc8f|common|#ffb347 656|Sturdy Wagon|biplane|gnome|#ddd5c7|#a3a380|#d08c60|common|#ffc971 657|Sleepy Lark|biplane|none|#b08968|#9a8c98|#bc6c25|common|#ffc971 658|Bronze Vulture|jet|none|#f97316|#f1f5f9|#a3e635|rare|#ff8c1a 659|Specter Phoenix|glider|gnome|#2e1065|#14532d|#ff6a00|epic|#39ff14 660|Faded Pony|prop|none|#7d8597|#6b705c|#3d405b|common|#ffb347 661|Sleepy Duck|biplane|none|#8d8d8d|#4f5d75|#c9a227|common|#ffd166 662|Rainy Starling|stunt|gnome|#8a9a5b|#4f5d75|#a44a3f|common|#ffe680 663|Second Kite|prop|none|#b5a27a|#5e6472|#f4f1de|common|#ffc971 664|Rusty Crane|biplane|none|#a89f91|#8c7b6b|#e9c46a|common|#fff1c1 665|Amber Raven|seaplane|gnome|#2563eb|#111827|#22d3ee|rare|#4dd2ff 666|Tangerine Cormorant|seaplane|gnome|#be185d|#fef3c7|#f472b6|rare|#4dd2ff 667|Azure Shrike|twin|gnome|#facc15|#f8fafc|#a3e635|rare|#ff4d4d 668|Canvas Tarmac|biplane|none|#a89f91|#5c5c5c|#3d405b|common|#ffc971 669|Patched Wren|prop|none|#ddd5c7|#5e6472|#c9a227|common|#ffb347 670|Sunday Plover|stunt|none|#ddd5c7|#7a6a53|#3d405b|common|#ffd166 671|Scruffy Pelican|stunt|none|#9c8f6e|#5c5c5c|#c9a227|common|#ffd166 672|Indigo Shrike|jet|gnome|#ea580c|#f1f5f9|#fbbf24|rare|#ff66c4 673|Saffron Viper|jet|none|#2563eb|#f1f5f9|#ef4444|rare|#7cff6b 674|Cloudy Swift|biplane|gnome|#b08968|#6b705c|#3d405b|common|#fff1c1 675|Coral Eagle|seaplane|gnome|#facc15|#f8fafc|#000000|rare|#ff4d4d 676|Ivory Merlin|seaplane|none|#facc15|#e2e8f0|#ffffff|rare|#ff4d4d 677|Slow Lark|biplane|gnome|#8a9a5b|#4f5d75|#bc6c25|common|#ffd166 678|Jade Falcon|seaplane|none|#2563eb|#fef3c7|#f472b6|rare|#9d8cff 679|Muddy Finch|prop|none|#a89f91|#a3a380|#a44a3f|common|#ffe680 680|Jade Kestrel|twin|none|#ea580c|#111827|#22d3ee|rare|#4dd2ff 681|Windy Wren|prop|none|#b08968|#9a8c98|#3d405b|common|#ffc971 682|Coral Harrier|seaplane|none|#7c3aed|#111827|#ef4444|rare|#ff8c1a 683|Quiet Tarmac|biplane|none|#8d8d8d|#5e6472|#e9c46a|common|#ffe680 684|Tidy Barrel|prop|none|#7d8597|#a3a380|#c9a227|common|#ffc971 685|Tangerine Falcon|seaplane|none|#15803d|#111827|#ef4444|rare|#9d8cff 686|Azure Viper|jet|gnome|#2563eb|#111827|#a3e635|rare|#ff4d4d 687|Humble Barrel|prop|none|#9b7e6b|#4f5d75|#a44a3f|common|#ffd166 688|Rainy Crane|biplane|gnome|#6b705c|#7a6a53|#c9a227|common|#ffd166 689|Brave Snipe|prop|none|#b08968|#7a6a53|#3d405b|common|#ffc971 690|Frost Warden|glider|gnome|#172554|#27272a|#00f5ff|epic|#f72585 691|Sturdy Finch|stunt|none|#ddd5c7|#7a6a53|#bc6c25|common|#ffd166 692|Thrifty Mallard|stunt|none|#8d8d8d|#5c5c5c|#e07a5f|common|#ffd166 693|Cheap Hangar|biplane|gnome|#aab7b8|#8c7b6b|#e07a5f|common|#ffc971 694|Honest Starling|biplane|none|#9b7e6b|#9a8c98|#c9a227|common|#fff1c1 695|Coral Cormorant|jet|gnome|#c1121f|#1e293b|#ef4444|rare|#ff4d4d 696|Steady Barrel|biplane|none|#aab7b8|#4f5d75|#c9a227|common|#fff1c1 697|Cheap Lantern|biplane|none|#7d8597|#56604a|#bc6c25|common|#ffb347 698|Spare Barrel|biplane|none|#8d8d8d|#8c7b6b|#c9a227|common|#fff1c1 699|Jade Merlin|seaplane|none|#1d4ed8|#fde68a|#f472b6|rare|#9d8cff 700|Emerald Mustang|jet|none|#c1121f|#0f172a|#fb923c|rare|#ffe14d 701|Canvas Bucket|biplane|none|#9b7e6b|#a3a380|#588157|common|#ffc971 702|Golden Eagle|seaplane|none|#ea580c|#111827|#22d3ee|rare|#4dd2ff 703|Windy Hangar|prop|none|#7d8597|#8c7b6b|#f4f1de|common|#ffc971 704|Simple Thrush|prop|none|#a89f91|#5c5c5c|#3d405b|common|#ffc971 705|Aurora Warden|glider|gnome|#1e1b4b|#1e3a8a|#00f5ff|epic|#00f5ff 706|Coral Hobby|twin|gnome|#c1121f|#e2e8f0|#ffffff|rare|#ff66c4 707|Omega Reaper|glider|gnome|#1e1b4b|#1e3a8a|#39ff14|epic|#7df9ff 708|Crimson Mustang|jet|gnome|#ea580c|#0f172a|#fb923c|rare|#ff66c4 709|Jade Goshawk|seaplane|none|#0891b2|#f1f5f9|#ef4444|rare|#9d8cff 710|Eclipse Warden|glider|gnome|#4a0404|#581c87|#ff4d6d|epic|#7df9ff 711|Faded Starling|biplane|none|#c2b280|#6b705c|#a44a3f|common|#ffc971 712|Tin Swift|biplane|gnome|#8a9a5b|#6f4e37|#e9c46a|common|#ffd166 713|Amber Corsair|seaplane|none|#facc15|#f1f5f9|#f472b6|rare|#ff4d4d 714|Comet Valkyrie|delta|gnome|#1e1b4b|#27272a|#f72585|epic|#ff9e00 715|Jade Caracara|seaplane|gnome|#0891b2|#0f172a|#a3e635|rare|#ff66c4 716|Chrome Viper|jet|gnome|#facc15|#111827|#000000|rare|#ffe14d 717|Indigo Gannet|twin|gnome|#1d4ed8|#fef3c7|#a3e635|rare|#ff8c1a 718|Comet Reaper|glider|gnome|#2e1065|#134e4a|#ff6a00|epic|#7df9ff 719|Plain Pigeon|biplane|none|#aab7b8|#5c5c5c|#f2cc8f|common|#ffe680 720|Rusty Plover|prop|gnome|#9c8f6e|#9a8c98|#bc6c25|common|#ffd166 721|Ruby Condor|twin|none|#0891b2|#1e293b|#22d3ee|rare|#ff66c4 722|Plain Finch|stunt|none|#ddd5c7|#6f4e37|#f2cc8f|common|#ffe680 723|Tangerine Hobby|jet|none|#facc15|#f1f5f9|#f472b6|rare|#ffe14d 724|Bronze Goshawk|seaplane|gnome|#15803d|#e2e8f0|#000000|rare|#ff66c4 725|Cobalt Lancer|jet|gnome|#7c3aed|#111827|#000000|rare|#ffe14d 726|Ivory Cormorant|twin|none|#ea580c|#1e293b|#000000|rare|#4dd2ff 727|Second Gull|prop|gnome|#7d8597|#4f5d75|#c9a227|common|#ffe680 728|Copper Cormorant|twin|none|#0891b2|#1e293b|#f472b6|rare|#ff4d4d 729|Copper Vulture|twin|gnome|#be185d|#0f172a|#a3e635|rare|#ff8c1a 730|Steady Bucket|prop|none|#8d8d8d|#56604a|#e07a5f|common|#ffc971 731|Humble Owl|prop|none|#b5a27a|#56604a|#d08c60|common|#fff1c1 732|Canvas Barrel|biplane|gnome|#aab7b8|#6f4e37|#f4f1de|common|#ffc971 733|Tidy Sparrow|biplane|none|#7d8597|#5e6472|#f4f1de|common|#fff1c1 734|Ivory Buzzard|seaplane|none|#2563eb|#0f172a|#f472b6|rare|#ffe14d 735|Crimson Goshawk|jet|none|#0891b2|#e2e8f0|#000000|rare|#4dd2ff 736|Tin Rook|stunt|none|#6b705c|#9a8c98|#a44a3f|common|#fff1c1 737|Chrome Harrier|twin|gnome|#15803d|#f1f5f9|#a3e635|rare|#ff66c4 738|Sturdy Owl|prop|none|#8d8d8d|#4f5d75|#bc6c25|common|#fff1c1 739|Gentle Wren|prop|none|#8d8d8d|#6f4e37|#c9a227|common|#fff1c1 740|Nova Oracle|glider|gnome|#0b1020|#134e4a|#00f5ff|epic|#00f5ff 741|Eclipse Herald|glider|gnome|#042f2e|#312e81|#ff4d6d|epic|#c77dff 742|Steady Lark|biplane|none|#c2b280|#5c5c5c|#e9c46a|common|#ffc971 743|Ivory Eagle|twin|none|#c1121f|#111827|#000000|rare|#ff4d4d 744|Cheap Crow|prop|none|#c2b280|#9a8c98|#e07a5f|common|#ffd166 745|Phantom Valkyrie|delta|gnome|#3b0764|#1e293b|#f72585|epic|#f72585 746|Neon Goshawk|seaplane|gnome|#2563eb|#1e293b|#fb923c|rare|#ff8c1a 747|Quiet Starling|biplane|none|#8a9a5b|#6b705c|#588157|common|#fff1c1 748|Sleepy Jay|prop|gnome|#7d8597|#8c7b6b|#e9c46a|common|#ffc971 749|Silver Albatross|jet|none|#2563eb|#111827|#ef4444|rare|#9d8cff 750|Amber Osprey|jet|gnome|#7c3aed|#111827|#a3e635|rare|#ffe14d 751|Dusty Snipe|stunt|none|#c2b280|#4f5d75|#c9a227|common|#fff1c1 752|Electric Goshawk|seaplane|gnome|#be185d|#0f172a|#22d3ee|rare|#9d8cff 753|Rural Stork|biplane|none|#aab7b8|#9a8c98|#bc6c25|common|#ffe680 754|Steady Mule|prop|none|#8a9a5b|#a3a380|#f2cc8f|common|#ffe680 755|Grey Dove|biplane|none|#ddd5c7|#a3a380|#3d405b|common|#ffe680 756|Bronze Harrier|jet|none|#facc15|#fef3c7|#a3e635|rare|#7cff6b 757|Nova Warden|delta|gnome|#042f2e|#1e293b|#39ff14|epic|#39ff14 758|Humble Quail|biplane|none|#8d8d8d|#a3a380|#e9c46a|common|#ffc971 759|Weary Crow|stunt|none|#b5a27a|#4f5d75|#e07a5f|common|#ffb347 760|Amber Vulture|twin|gnome|#ea580c|#0f172a|#ffffff|rare|#ff66c4 761|Loyal Jay|biplane|none|#9b7e6b|#6f4e37|#588157|common|#ffc971 762|Thunder Titan|delta|gnome|#3b0764|#1e293b|#ffd60a|epic|#f72585 763|Grey Pelican|stunt|none|#6b705c|#5e6472|#e07a5f|common|#ffb347 764|Amber Cormorant|seaplane|none|#be185d|#fde68a|#f472b6|rare|#4dd2ff 765|Simple Rook|biplane|none|#7d8597|#6b705c|#3d405b|common|#ffe680 766|Spare Jay|stunt|none|#6b705c|#8c7b6b|#c9a227|common|#ffb347 767|Gentle Duck|stunt|none|#6b705c|#8c7b6b|#d08c60|common|#ffc971 768|Sturdy Starling|prop|none|#7d8597|#5e6472|#3d405b|common|#ffe680 769|Rusty Sparrow|biplane|none|#b08968|#5c5c5c|#a44a3f|common|#ffe680 770|Rusty Snipe|prop|gnome|#7d8597|#7a6a53|#c9a227|common|#ffc971 771|Foggy Wagon|biplane|none|#aab7b8|#5c5c5c|#588157|common|#fff1c1 772|Cheap Tarmac|biplane|none|#aab7b8|#5e6472|#d08c60|common|#fff1c1 773|Aurora Banshee|delta|gnome|#052e16|#1e293b|#ffd60a|epic|#39ff14 774|Simple Duck|stunt|none|#9c8f6e|#9a8c98|#f2cc8f|common|#ffc971 775|Indigo Hawk|jet|gnome|#ea580c|#f8fafc|#f472b6|rare|#ff8c1a 776|Steady Crow|prop|none|#8d8d8d|#6b705c|#3d405b|common|#ffc971 777|SuperGnome|supergnome|none|#c1121f|#1d4ed8|#ffd700|legendary|#ff2e2e`
- #24/gno.MemPackageType
Result log
msg:0,success:true,log:,events:[]