mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-03-20 16:55:22 +00:00
[Feature] Tera Rework (#5233)
* Commit old stashed changes * Complete basic implementation of Tera * Fix effectiveness test * Make tera retain until forced recall or faint, regain on biome change * Experimental sparkle fix * Fix champion teras * Attempted fix for double battles tera UI bug * Fix the fix * Fix linting and test issues * Fix more tests * Change int type * Implement tera for ME trainers * Cleanup species inclusivity check * Make tera instant recharge if terapagos in party * Make useless tera shards not generate * Implement stellar tera damage boost * Improve tera selection UI * Tidy up animation and localisation * Improve tera button sprite * Fix Lance tera * Make tera instant recharge during E4 in classic modes. * Fix formatting in the tera common animation The animation was also not playing due to `frameTimedEvents` being missing as well. * Make tera effect start after animation * Implement save migration * Update version number for migration code --------- Co-authored-by: Madmadness65 <blaze.the.fireman@gmail.com> Co-authored-by: Madmadness65 <59298170+Madmadness65@users.noreply.github.com>
This commit is contained in:
parent
4bc617bd5f
commit
90d32b886c
774
public/battle-anims/common-terastallize.json
Normal file
774
public/battle-anims/common-terastallize.json
Normal file
@ -0,0 +1,774 @@
|
||||
{
|
||||
"graphic": "terastallize",
|
||||
"frames": [
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 150,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 225,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 70,
|
||||
"zoomY": 70,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 70,
|
||||
"zoomY": 70,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 90,
|
||||
"zoomY": 90,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 90,
|
||||
"zoomY": 90,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 255,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 200,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 100,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 100,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 60,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 60,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -20,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 2,
|
||||
"graphicFrame": 1,
|
||||
"opacity": 60,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
0
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 0,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"tone": [
|
||||
255,
|
||||
255,
|
||||
255,
|
||||
255
|
||||
],
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 2
|
||||
},
|
||||
{
|
||||
"x": 128,
|
||||
"y": -64,
|
||||
"zoomX": 100,
|
||||
"zoomY": 100,
|
||||
"visible": true,
|
||||
"target": 1,
|
||||
"graphicFrame": 0,
|
||||
"opacity": 255,
|
||||
"locked": true,
|
||||
"priority": 1,
|
||||
"focus": 1
|
||||
}
|
||||
]
|
||||
],
|
||||
"frameTimedEvents": {},
|
||||
"position": 4,
|
||||
"hue": 0
|
||||
}
|
BIN
public/images/battle_anims/terastallize.png
Normal file
BIN
public/images/battle_anims/terastallize.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
158
public/images/ui/button_tera.json
Normal file
158
public/images/ui/button_tera.json
Normal file
@ -0,0 +1,158 @@
|
||||
{ "frames": {
|
||||
"unknown": {
|
||||
"frame": { "x": 0, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"bug": {
|
||||
"frame": { "x": 18, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"dark": {
|
||||
"frame": { "x": 36, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"dragon": {
|
||||
"frame": { "x": 54, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"electric": {
|
||||
"frame": { "x": 72, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fairy": {
|
||||
"frame": { "x": 0, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fighting": {
|
||||
"frame": { "x": 18, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fire": {
|
||||
"frame": { "x": 36, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"flying": {
|
||||
"frame": { "x": 54, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ghost": {
|
||||
"frame": { "x": 72, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"grass": {
|
||||
"frame": { "x": 0, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ground": {
|
||||
"frame": { "x": 18, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ice": {
|
||||
"frame": { "x": 36, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"normal": {
|
||||
"frame": { "x": 54, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"poison": {
|
||||
"frame": { "x": 72, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"psychic": {
|
||||
"frame": { "x": 0, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"rock": {
|
||||
"frame": { "x": 18, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"steel": {
|
||||
"frame": { "x": 36, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"water": {
|
||||
"frame": { "x": 54, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"stellar": {
|
||||
"frame": { "x": 72, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"app": "https://www.aseprite.org/",
|
||||
"version": "1.3.7-dev",
|
||||
"image": "button_tera.png",
|
||||
"format": "RGBA8888",
|
||||
"size": { "w": 90, "h": 84 },
|
||||
"scale": "1",
|
||||
"frameTags": [
|
||||
],
|
||||
"layers": [
|
||||
{ "name": "Sprite Sheet", "opacity": 255, "blendMode": "normal" }
|
||||
],
|
||||
"slices": [
|
||||
]
|
||||
}
|
||||
}
|
BIN
public/images/ui/button_tera.png
Normal file
BIN
public/images/ui/button_tera.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
158
public/images/ui/legacy/button_tera.json
Normal file
158
public/images/ui/legacy/button_tera.json
Normal file
@ -0,0 +1,158 @@
|
||||
{ "frames": {
|
||||
"unknown": {
|
||||
"frame": { "x": 0, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"bug": {
|
||||
"frame": { "x": 18, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"dark": {
|
||||
"frame": { "x": 36, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"dragon": {
|
||||
"frame": { "x": 54, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"electric": {
|
||||
"frame": { "x": 72, "y": 0, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fairy": {
|
||||
"frame": { "x": 0, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fighting": {
|
||||
"frame": { "x": 18, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"fire": {
|
||||
"frame": { "x": 36, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"flying": {
|
||||
"frame": { "x": 54, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ghost": {
|
||||
"frame": { "x": 72, "y": 21, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"grass": {
|
||||
"frame": { "x": 0, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ground": {
|
||||
"frame": { "x": 18, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"ice": {
|
||||
"frame": { "x": 36, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"normal": {
|
||||
"frame": { "x": 54, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"poison": {
|
||||
"frame": { "x": 72, "y": 42, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"psychic": {
|
||||
"frame": { "x": 0, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"rock": {
|
||||
"frame": { "x": 18, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"steel": {
|
||||
"frame": { "x": 36, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"water": {
|
||||
"frame": { "x": 54, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
},
|
||||
"stellar": {
|
||||
"frame": { "x": 72, "y": 63, "w": 18, "h": 21 },
|
||||
"rotated": false,
|
||||
"trimmed": true,
|
||||
"spriteSourceSize": { "x": 1, "y": 1, "w": 18, "h": 21 },
|
||||
"sourceSize": { "w": 20, "h": 23 }
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"app": "https://www.aseprite.org/",
|
||||
"version": "1.3.7-dev",
|
||||
"image": "button_tera.png",
|
||||
"format": "RGBA8888",
|
||||
"size": { "w": 90, "h": 84 },
|
||||
"scale": "1",
|
||||
"frameTags": [
|
||||
],
|
||||
"layers": [
|
||||
{ "name": "Sprite Sheet", "opacity": 255, "blendMode": "normal" }
|
||||
],
|
||||
"slices": [
|
||||
]
|
||||
}
|
||||
}
|
BIN
public/images/ui/legacy/button_tera.png
Normal file
BIN
public/images/ui/legacy/button_tera.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
@ -9,7 +9,7 @@ import type { Constructor } from "#app/utils";
|
||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import * as Utils from "#app/utils";
|
||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, ModifierBar, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier, TerastallizeModifier } from "./modifier/modifier";
|
||||
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, ModifierBar, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier } from "./modifier/modifier";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "#app/data/battle-anims";
|
||||
import type { Phase } from "#app/phase";
|
||||
@ -1373,7 +1373,11 @@ export default class BattleScene extends SceneBase {
|
||||
|
||||
for (const pokemon of this.getPlayerParty()) {
|
||||
pokemon.resetBattleData();
|
||||
pokemon.resetTera();
|
||||
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
|
||||
if (pokemon.hasSpecies(Species.TERAPAGOS) || (this.gameMode.isClassic && this.currentBattle.waveIndex > 180 && this.currentBattle.waveIndex <= 190)) {
|
||||
this.arena.playerTerasUsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.trainer.visible) {
|
||||
@ -1658,7 +1662,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
|
||||
initPokemonSprite(sprite: Phaser.GameObjects.Sprite, pokemon?: Pokemon, hasShadow: boolean = false, ignoreOverride: boolean = false): Phaser.GameObjects.Sprite {
|
||||
sprite.setPipeline(this.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: hasShadow, ignoreOverride: ignoreOverride, teraColor: pokemon ? getTypeRgb(pokemon.getTeraType()) : undefined });
|
||||
sprite.setPipeline(this.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: hasShadow, ignoreOverride: ignoreOverride, teraColor: pokemon ? getTypeRgb(pokemon.getTeraType()) : undefined, isTerastallized: pokemon ? pokemon.isTerastallized : false });
|
||||
this.spriteSparkleHandler.add(sprite);
|
||||
return sprite;
|
||||
}
|
||||
@ -2589,11 +2593,8 @@ export default class BattleScene extends SceneBase {
|
||||
const modifiersToRemove: PersistentModifier[] = [];
|
||||
const modifierPromises: Promise<boolean>[] = [];
|
||||
if (modifier instanceof PersistentModifier) {
|
||||
if (modifier instanceof TerastallizeModifier) {
|
||||
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId)));
|
||||
}
|
||||
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual)) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
||||
if (pokemon) {
|
||||
success = modifier.apply(pokemon, true);
|
||||
@ -2670,11 +2671,8 @@ export default class BattleScene extends SceneBase {
|
||||
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const modifiersToRemove: PersistentModifier[] = [];
|
||||
if (modifier instanceof TerastallizeModifier) {
|
||||
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId, false)));
|
||||
}
|
||||
if ((modifier as PersistentModifier).add(this.enemyModifiers, false)) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
||||
if (pokemon) {
|
||||
modifier.apply(pokemon, true);
|
||||
@ -2798,6 +2796,8 @@ export default class BattleScene extends SceneBase {
|
||||
for (const modifier of modifiers) {
|
||||
this.addEnemyModifier(modifier, true, true);
|
||||
}
|
||||
|
||||
this.currentBattle.trainer.genAI(party);
|
||||
}
|
||||
|
||||
party.forEach((enemyPokemon: EnemyPokemon, i: number) => {
|
||||
@ -2929,7 +2929,7 @@ export default class BattleScene extends SceneBase {
|
||||
const modifierIndex = modifiers.indexOf(modifier);
|
||||
if (modifierIndex > -1) {
|
||||
modifiers.splice(modifierIndex, 1);
|
||||
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) {
|
||||
if (modifier instanceof PokemonFormChangeItemModifier) {
|
||||
const pokemon = this.getPokemonById(modifier.pokemonId);
|
||||
if (pokemon) {
|
||||
modifier.apply(pokemon, false);
|
||||
@ -3130,7 +3130,8 @@ export default class BattleScene extends SceneBase {
|
||||
name: p.name,
|
||||
form: p.getFormKey(),
|
||||
types: p.getTypes().map((type) => Type[type]),
|
||||
teraType: p.getTeraType() !== Type.UNKNOWN ? Type[p.getTeraType()] : "",
|
||||
teraType: Type[p.getTeraType()],
|
||||
isTerastallized: p.isTerastallized,
|
||||
level: p.level,
|
||||
currentHP: p.hp,
|
||||
maxHP: p.getMaxHp(),
|
||||
|
@ -92,6 +92,7 @@ export default class Battle {
|
||||
public started: boolean = false;
|
||||
public enemySwitchCounter: number = 0;
|
||||
public turn: number = 0;
|
||||
public preTurnCommands: TurnCommands;
|
||||
public turnCommands: TurnCommands;
|
||||
public playerParticipantIds: Set<number> = new Set<number>();
|
||||
public battleScore: number = 0;
|
||||
@ -180,6 +181,7 @@ export default class Battle {
|
||||
incrementTurn(): void {
|
||||
this.turn++;
|
||||
this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [ bt, null ]));
|
||||
this.preTurnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [ bt, null ]));
|
||||
this.battleSeedState = null;
|
||||
}
|
||||
|
||||
|
@ -239,37 +239,25 @@ export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
export class PostBattleInitStatStageChangeAbAttr extends PostBattleInitAbAttr {
|
||||
export class PostTeraFormChangeStatChangeAbAttr extends AbAttr {
|
||||
private stats: BattleStat[];
|
||||
private stages: number;
|
||||
private selfTarget: boolean;
|
||||
|
||||
constructor(stats: BattleStat[], stages: number, selfTarget?: boolean) {
|
||||
constructor(stats: BattleStat[], stages: number) {
|
||||
super();
|
||||
|
||||
this.stats = stats;
|
||||
this.stages = stages;
|
||||
this.selfTarget = !!selfTarget;
|
||||
}
|
||||
|
||||
applyPostBattleInit(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise<boolean> {
|
||||
const statStageChangePhases: StatStageChangePhase[] = [];
|
||||
|
||||
if (!simulated) {
|
||||
if (this.selfTarget) {
|
||||
statStageChangePhases.push(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
||||
} else {
|
||||
for (const opponent of pokemon.getOpponents()) {
|
||||
statStageChangePhases.push(new StatStageChangePhase(opponent.getBattlerIndex(), false, this.stats, this.stages));
|
||||
}
|
||||
}
|
||||
statStageChangePhases.push(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
||||
|
||||
for (const statStageChangePhase of statStageChangePhases) {
|
||||
if (!this.selfTarget && !statStageChangePhase.getPokemon()?.summonData) {
|
||||
globalScene.pushPhase(statStageChangePhase);
|
||||
} else { // TODO: This causes the ability bar to be shown at the wrong time
|
||||
globalScene.unshiftPhase(statStageChangePhase);
|
||||
}
|
||||
globalScene.unshiftPhase(statStageChangePhase);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1307,7 +1295,7 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
|
||||
|
||||
applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (
|
||||
!pokemon.isTerastallized() &&
|
||||
!pokemon.isTerastallized &&
|
||||
move.id !== Moves.STRUGGLE &&
|
||||
/**
|
||||
* Skip moves that call other moves because these moves generate a following move that will trigger this ability attribute
|
||||
@ -4788,7 +4776,7 @@ export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr {
|
||||
}
|
||||
|
||||
override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, _args: any[]): boolean {
|
||||
if (pokemon.isTerastallized()) {
|
||||
if (pokemon.isTerastallized) {
|
||||
return false;
|
||||
}
|
||||
const currentTerrain = globalScene.arena.getTerrainType();
|
||||
@ -6201,7 +6189,7 @@ export function initAbilities() {
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.attr(NoFusionAbilityAbAttr)
|
||||
.condition((pokemon) => !pokemon.isTerastallized()),
|
||||
.condition((pokemon) => !pokemon.isTerastallized),
|
||||
new Ability(Abilities.QUICK_DRAW, 8)
|
||||
.attr(BypassSpeedChanceAbAttr, 30),
|
||||
new Ability(Abilities.UNSEEN_FIST, 8)
|
||||
@ -6353,29 +6341,25 @@ export function initAbilities() {
|
||||
new Ability(Abilities.TOXIC_CHAIN, 9)
|
||||
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
|
||||
new Ability(Abilities.EMBODY_ASPECT_TEAL, 9)
|
||||
.attr(PostBattleInitStatStageChangeAbAttr, [ Stat.SPD ], 1, true)
|
||||
.attr(PostTeraFormChangeStatChangeAbAttr, [ Stat.SPD ], 1)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.partial(), // Ogerpon tera interactions
|
||||
.attr(NoTransformAbilityAbAttr),
|
||||
new Ability(Abilities.EMBODY_ASPECT_WELLSPRING, 9)
|
||||
.attr(PostBattleInitStatStageChangeAbAttr, [ Stat.SPDEF ], 1, true)
|
||||
.attr(PostTeraFormChangeStatChangeAbAttr, [ Stat.SPDEF ], 1)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.partial(), // Ogerpon tera interactions
|
||||
.attr(NoTransformAbilityAbAttr),
|
||||
new Ability(Abilities.EMBODY_ASPECT_HEARTHFLAME, 9)
|
||||
.attr(PostBattleInitStatStageChangeAbAttr, [ Stat.ATK ], 1, true)
|
||||
.attr(PostTeraFormChangeStatChangeAbAttr, [ Stat.ATK ], 1)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.partial(), // Ogerpon tera interactions
|
||||
.attr(NoTransformAbilityAbAttr),
|
||||
new Ability(Abilities.EMBODY_ASPECT_CORNERSTONE, 9)
|
||||
.attr(PostBattleInitStatStageChangeAbAttr, [ Stat.DEF ], 1, true)
|
||||
.attr(PostTeraFormChangeStatChangeAbAttr, [ Stat.DEF ], 1)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
.attr(NoTransformAbilityAbAttr)
|
||||
.partial(), // Ogerpon tera interactions
|
||||
.attr(NoTransformAbilityAbAttr),
|
||||
new Ability(Abilities.TERA_SHIFT, 9)
|
||||
.attr(PostSummonFormChangeAbAttr, p => p.getFormKey() ? 0 : 1)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
|
@ -56,6 +56,7 @@ export enum ChargeAnim {
|
||||
export enum CommonAnim {
|
||||
USE_ITEM = 2000,
|
||||
HEALTH_UP,
|
||||
TERASTALLIZE,
|
||||
POISON = 2010,
|
||||
TOXIC,
|
||||
PARALYSIS,
|
||||
|
@ -2485,7 +2485,7 @@ export class TarShotTag extends BattlerTag {
|
||||
* @returns whether the tag is applied
|
||||
*/
|
||||
override canAdd(pokemon: Pokemon): boolean {
|
||||
return !pokemon.isTerastallized();
|
||||
return !pokemon.isTerastallized;
|
||||
}
|
||||
|
||||
override onAdd(pokemon: Pokemon): void {
|
||||
|
@ -791,7 +791,7 @@ export default class Move implements Localizable {
|
||||
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, source, target, this, true, null, typeChangeMovePowerMultiplier);
|
||||
|
||||
const sourceTeraType = source.getTeraType();
|
||||
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
|
||||
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
|
||||
power.value = 60;
|
||||
}
|
||||
|
||||
@ -4634,7 +4634,7 @@ export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const category = (args[0] as Utils.NumberHolder);
|
||||
|
||||
if (user.isTerastallized() && user.getEffectiveStat(Stat.ATK, target, move, true, true, false, false, true) >
|
||||
if (user.isTerastallized && user.getEffectiveStat(Stat.ATK, target, move, true, true, false, false, true) >
|
||||
user.getEffectiveStat(Stat.SPATK, target, move, true, true, false, false, true)) {
|
||||
category.value = MoveCategory.PHYSICAL;
|
||||
return true;
|
||||
@ -4662,7 +4662,7 @@ export class TeraBlastPowerAttr extends VariablePowerAttr {
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const power = args[0] as Utils.NumberHolder;
|
||||
if (user.isTerastallized() && user.getTeraType() === Type.STELLAR) {
|
||||
if (user.isTerastallized && user.getTeraType() === Type.STELLAR) {
|
||||
power.value = 100;
|
||||
return true;
|
||||
}
|
||||
@ -4720,30 +4720,6 @@ export class VariableMoveTypeAttr extends MoveAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used for Tera Starstorm that changes the move type to Stellar
|
||||
* @extends VariableMoveTypeAttr
|
||||
*/
|
||||
export class TeraStarstormTypeAttr extends VariableMoveTypeAttr {
|
||||
/**
|
||||
*
|
||||
* @param user the {@linkcode Pokemon} using the move
|
||||
* @param target n/a
|
||||
* @param move n/a
|
||||
* @param args[0] {@linkcode Utils.NumberHolder} the move type
|
||||
* @returns `true` if the move type is changed to {@linkcode Type.STELLAR}, `false` otherwise
|
||||
*/
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (user.isTerastallized() && (user.hasFusionSpecies(Species.TERAPAGOS) || user.species.speciesId === Species.TERAPAGOS)) {
|
||||
const moveType = args[0] as Utils.NumberHolder;
|
||||
|
||||
moveType.value = Type.STELLAR;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class FormChangeItemTypeAttr extends VariableMoveTypeAttr {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const moveType = args[0];
|
||||
@ -5009,7 +4985,7 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user.isTerastallized()) {
|
||||
if (user.isTerastallized) {
|
||||
moveType.value = user.getTeraType(); // changes move type to tera type
|
||||
return true;
|
||||
}
|
||||
@ -5018,6 +4994,30 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used for Tera Starstorm that changes the move type to Stellar
|
||||
* @extends VariableMoveTypeAttr
|
||||
*/
|
||||
export class TeraStarstormTypeAttr extends VariableMoveTypeAttr {
|
||||
/**
|
||||
*
|
||||
* @param user the {@linkcode Pokemon} using the move
|
||||
* @param target n/a
|
||||
* @param move n/a
|
||||
* @param args[0] {@linkcode Utils.NumberHolder} the move type
|
||||
* @returns `true` if the move type is changed to {@linkcode Type.STELLAR}, `false` otherwise
|
||||
*/
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (user.isTerastallized && user.hasSpecies(Species.TERAPAGOS)) {
|
||||
const moveType = args[0] as Utils.NumberHolder;
|
||||
|
||||
moveType.value = Type.STELLAR;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class MatchUserTypeAttr extends VariableMoveTypeAttr {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const moveType = args[0];
|
||||
@ -6345,7 +6345,7 @@ export class RemoveTypeAttr extends MoveEffectAttr {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user.isTerastallized() && user.getTeraType() === this.removedType) { // active tera types cannot be removed
|
||||
if (user.isTerastallized && user.getTeraType() === this.removedType) { // active tera types cannot be removed
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -6525,7 +6525,7 @@ export class ChangeTypeAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
getCondition(): MoveConditionFunc {
|
||||
return (user, target, move) => !target.isTerastallized() && !target.hasAbility(Abilities.MULTITYPE) && !target.hasAbility(Abilities.RKS_SYSTEM) && !(target.getTypes().length === 1 && target.getTypes()[0] === this.type);
|
||||
return (user, target, move) => !target.isTerastallized && !target.hasAbility(Abilities.MULTITYPE) && !target.hasAbility(Abilities.RKS_SYSTEM) && !(target.getTypes().length === 1 && target.getTypes()[0] === this.type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6548,7 +6548,7 @@ export class AddTypeAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
getCondition(): MoveConditionFunc {
|
||||
return (user, target, move) => !target.isTerastallized() && !target.getTypes().includes(this.type);
|
||||
return (user, target, move) => !target.isTerastallized && !target.getTypes().includes(this.type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11076,7 +11076,7 @@ export function initMoves() {
|
||||
.attr(TeraMoveCategoryAttr)
|
||||
.attr(TeraBlastTypeAttr)
|
||||
.attr(TeraBlastPowerAttr)
|
||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1, true, { condition: (user, target, move) => user.isTerastallized() && user.isOfType(Type.STELLAR) }),
|
||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1, true, { condition: (user, target, move) => user.isTerastallized && user.isOfType(Type.STELLAR) }),
|
||||
new SelfStatusMove(Moves.SILK_TRAP, Type.BUG, -1, 10, -1, 4, 9)
|
||||
.attr(ProtectAttr, BattlerTagType.SILK_TRAP)
|
||||
.condition(failIfLastCondition),
|
||||
@ -11271,7 +11271,7 @@ export function initMoves() {
|
||||
new AttackMove(Moves.TERA_STARSTORM, Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9)
|
||||
.attr(TeraMoveCategoryAttr)
|
||||
.attr(TeraStarstormTypeAttr)
|
||||
.attr(VariableTargetAttr, (user, target, move) => (user.hasFusionSpecies(Species.TERAPAGOS) || user.species.speciesId === Species.TERAPAGOS) && user.isTerastallized() ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER)
|
||||
.attr(VariableTargetAttr, (user, target, move) => user.hasSpecies(Species.TERAPAGOS) && user.isTerastallized ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER)
|
||||
.partial(), /** Does not ignore abilities that affect stats, relevant in determining the move's category {@see TeraMoveCategoryAttr} */
|
||||
new AttackMove(Moves.FICKLE_BEAM, Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9)
|
||||
.attr(PreMoveMessageAttr, doublePowerChanceMessageFunc)
|
||||
|
@ -594,7 +594,7 @@ function doPokemonTradeSequence(tradedPokemon: PlayerPokemon, receivedPokemon: P
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()), isTerastallized: tradedPokemon.isTerastallized });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", tradedPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", tradedPokemon.shiny);
|
||||
@ -615,7 +615,7 @@ function doPokemonTradeSequence(tradedPokemon: PlayerPokemon, receivedPokemon: P
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(tradedPokemon.getTeraType()), isTerastallized: tradedPokemon.isTerastallized });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", receivedPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", receivedPokemon.shiny);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { generateModifierType, handleMysteryEncounterBattleFailed, initBattleWithEnemyConfig, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { handleMysteryEncounterBattleFailed, initBattleWithEnemyConfig, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||
import { trainerConfigs } from "#app/data/trainer-config";
|
||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
@ -23,7 +23,6 @@ import { EggSourceType } from "#enums/egg-source-types";
|
||||
import { EggTier } from "#enums/egg-type";
|
||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||
import { Type } from "#enums/type";
|
||||
import { getPokeballTintColor } from "#app/data/pokeball";
|
||||
@ -387,11 +386,7 @@ function getPartyConfig(): EnemyPartyConfig {
|
||||
nature: Nature.ADAMANT,
|
||||
moveSet: [ Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH ],
|
||||
ivs: [ 31, 31, 31, 31, 31, 31 ],
|
||||
modifierConfigs: [
|
||||
{
|
||||
modifier: generateModifierType(modifierTypes.TERA_SHARD, [ Type.STEEL ]) as PokemonHeldItemModifierType,
|
||||
}
|
||||
]
|
||||
tera: Type.STEEL,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -46,6 +46,7 @@ import type { Variant } from "#app/data/variant";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||
import { Type } from "#app/enums/type";
|
||||
|
||||
/**
|
||||
* Animates exclamation sprite over trainer's head at start of encounter
|
||||
@ -98,6 +99,7 @@ export interface EnemyPokemonConfig {
|
||||
modifierConfigs?: HeldModifierConfig[];
|
||||
tags?: BattlerTagType[];
|
||||
dataSource?: PokemonData;
|
||||
tera?: Type;
|
||||
aiType?: AiType;
|
||||
}
|
||||
|
||||
@ -329,6 +331,14 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
|
||||
tags.forEach(tag => enemyPokemon.addTag(tag));
|
||||
}
|
||||
|
||||
// Set tera
|
||||
if (config.tera && config.tera !== Type.UNKNOWN) {
|
||||
enemyPokemon.teraType = config.tera;
|
||||
if (battle.trainer) {
|
||||
battle.trainer.config.setInstantTera(e);
|
||||
}
|
||||
}
|
||||
|
||||
// mysteryEncounterBattleEffects will only be used IFF MYSTERY_ENCOUNTER_POST_SUMMON tag is applied
|
||||
if (config.mysteryEncounterBattleEffects) {
|
||||
enemyPokemon.mysteryEncounterBattleEffects = config.mysteryEncounterBattleEffects;
|
||||
|
@ -61,7 +61,7 @@ export function doPokemonTransformationSequence(previousPokemon: PlayerPokemon,
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(previousPokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(previousPokemon.getTeraType()), isTerastallized: previousPokemon.isTerastallized });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", previousPokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", previousPokemon.shiny);
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { PokemonFormChangeItemModifier, TerastallizeModifier } from "../modifier/modifier";
|
||||
import { PokemonFormChangeItemModifier } from "../modifier/modifier";
|
||||
import type Pokemon from "../field/pokemon";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { MoveCategory, allMoves } from "./move";
|
||||
import { Type } from "#enums/type";
|
||||
import type { Constructor, nil } from "#app/utils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
@ -399,23 +398,7 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
|
||||
* @extends SpeciesFormChangeTrigger
|
||||
*/
|
||||
export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {
|
||||
/** The Tera type that triggers the form change */
|
||||
private teraType: Type;
|
||||
|
||||
constructor(teraType: Type) {
|
||||
super();
|
||||
this.teraType = teraType;
|
||||
this.description = i18next.t("pokemonEvolutions:Forms.tera", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the associated Pokémon has the required Tera Shard that matches with the associated Tera type.
|
||||
* @param {Pokemon} pokemon the Pokémon that is trying to do the form change
|
||||
* @returns `true` if the Pokémon can change forms, `false` otherwise
|
||||
*/
|
||||
canChange(pokemon: Pokemon): boolean {
|
||||
return !!globalScene.findModifier(m => m instanceof TerastallizeModifier && m.pokemonId === pokemon.id && m.teraType === this.teraType);
|
||||
}
|
||||
description = i18next.t("pokemonEvolutions:Forms.tera" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -425,10 +408,6 @@ export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {
|
||||
*/
|
||||
export class SpeciesFormChangeLapseTeraTrigger extends SpeciesFormChangeTrigger {
|
||||
description = i18next.t("pokemonEvolutions:Forms.teraLapse");
|
||||
|
||||
canChange(pokemon: Pokemon): boolean {
|
||||
return !!globalScene.findModifier(m => m instanceof TerastallizeModifier && m.pokemonId === pokemon.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -992,19 +971,19 @@ export const pokemonFormChanges: PokemonFormChanges = {
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask", "wellspring-mask", new SpeciesFormChangeItemTrigger(FormChangeItem.WELLSPRING_MASK)),
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask", "hearthflame-mask", new SpeciesFormChangeItemTrigger(FormChangeItem.HEARTHFLAME_MASK)),
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask", "cornerstone-mask", new SpeciesFormChangeItemTrigger(FormChangeItem.CORNERSTONE_MASK)),
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask", "teal-mask-tera", new SpeciesFormChangeTeraTrigger(Type.GRASS)),
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask-tera", "teal-mask", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.GRASS)),
|
||||
new SpeciesFormChange(Species.OGERPON, "wellspring-mask", "wellspring-mask-tera", new SpeciesFormChangeTeraTrigger(Type.WATER)),
|
||||
new SpeciesFormChange(Species.OGERPON, "wellspring-mask-tera", "wellspring-mask", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.WATER)),
|
||||
new SpeciesFormChange(Species.OGERPON, "hearthflame-mask", "hearthflame-mask-tera", new SpeciesFormChangeTeraTrigger(Type.FIRE)),
|
||||
new SpeciesFormChange(Species.OGERPON, "hearthflame-mask-tera", "hearthflame-mask", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.FIRE)),
|
||||
new SpeciesFormChange(Species.OGERPON, "cornerstone-mask", "cornerstone-mask-tera", new SpeciesFormChangeTeraTrigger(Type.ROCK)),
|
||||
new SpeciesFormChange(Species.OGERPON, "cornerstone-mask-tera", "cornerstone-mask", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.ROCK))
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask", "teal-mask-tera", new SpeciesFormChangeTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "teal-mask-tera", "teal-mask", new SpeciesFormChangeLapseTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "wellspring-mask", "wellspring-mask-tera", new SpeciesFormChangeTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "wellspring-mask-tera", "wellspring-mask", new SpeciesFormChangeLapseTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "hearthflame-mask", "hearthflame-mask-tera", new SpeciesFormChangeTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "hearthflame-mask-tera", "hearthflame-mask", new SpeciesFormChangeLapseTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "cornerstone-mask", "cornerstone-mask-tera", new SpeciesFormChangeTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.OGERPON, "cornerstone-mask-tera", "cornerstone-mask", new SpeciesFormChangeLapseTeraTrigger(), true)
|
||||
],
|
||||
[Species.TERAPAGOS]: [
|
||||
new SpeciesFormChange(Species.TERAPAGOS, "", "terastal", new SpeciesFormChangeAbilityTrigger(), true),
|
||||
new SpeciesFormChange(Species.TERAPAGOS, "terastal", "stellar", new SpeciesFormChangeTeraTrigger(Type.STELLAR)),
|
||||
new SpeciesFormChange(Species.TERAPAGOS, "stellar", "terastal", new SpeciesFormChangeLapseTeraTrigger(), true, new SpeciesFormChangeCondition(p => p.getTeraType() !== Type.STELLAR))
|
||||
new SpeciesFormChange(Species.TERAPAGOS, "terastal", "stellar", new SpeciesFormChangeTeraTrigger(), true),
|
||||
new SpeciesFormChange(Species.TERAPAGOS, "stellar", "terastal", new SpeciesFormChangeLapseTeraTrigger(), true)
|
||||
],
|
||||
[Species.GALAR_DARMANITAN]: [
|
||||
new SpeciesFormChange(Species.GALAR_DARMANITAN, "", "zen", new SpeciesFormChangeAbilityTrigger(), true),
|
||||
|
@ -175,11 +175,51 @@ export const trainerPartyTemplates = {
|
||||
type PartyTemplateFunc = () => TrainerPartyTemplate;
|
||||
type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon;
|
||||
type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[];
|
||||
type GenAIFunc = (party: EnemyPokemon[]) => void;
|
||||
|
||||
export interface PartyMemberFuncs {
|
||||
[key: number]: PartyMemberFunc
|
||||
}
|
||||
|
||||
export enum TeraAIMode {
|
||||
NO_TERA,
|
||||
INSTANT_TERA,
|
||||
SMART_TERA
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores data and helper functions about a trainers AI options.
|
||||
*/
|
||||
export class TrainerAI {
|
||||
public teraMode: TeraAIMode = TeraAIMode.NO_TERA;
|
||||
public instantTeras: number[];
|
||||
|
||||
/**
|
||||
* @param canTerastallize Whether this trainer is allowed to tera
|
||||
*/
|
||||
constructor(teraMode: TeraAIMode = TeraAIMode.NO_TERA) {
|
||||
this.teraMode = teraMode;
|
||||
this.instantTeras = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a trainer can tera
|
||||
* @returns Whether this trainer can currently tera
|
||||
*/
|
||||
public canTerastallize() {
|
||||
return this.teraMode !== TeraAIMode.NO_TERA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a pokemon on this AI to just instantly tera on first move used
|
||||
* @param index The index of the pokemon to instantly tera
|
||||
*/
|
||||
public setInstantTera(index: number) {
|
||||
this.teraMode = TeraAIMode.INSTANT_TERA;
|
||||
this.instantTeras.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
export class TrainerConfig {
|
||||
public trainerType: TrainerType;
|
||||
public trainerTypeDouble: TrainerType;
|
||||
@ -203,6 +243,7 @@ export class TrainerConfig {
|
||||
public doubleEncounterBgm: string;
|
||||
public victoryBgm: string;
|
||||
public genModifiersFunc: GenModifiersFunc;
|
||||
public genAIFuncs: GenAIFunc[] = [];
|
||||
public modifierRewardFuncs: ModifierTypeFunc[] = [];
|
||||
public partyTemplates: TrainerPartyTemplate[];
|
||||
public partyTemplateFunc: PartyTemplateFunc;
|
||||
@ -212,6 +253,7 @@ export class TrainerConfig {
|
||||
public speciesFilter: PokemonSpeciesFilter;
|
||||
public specialtyTypes: Type[] = [];
|
||||
public hasVoucher: boolean = false;
|
||||
public trainerAI: TrainerAI;
|
||||
|
||||
public encounterMessages: string[] = [];
|
||||
public victoryMessages: string[] = [];
|
||||
@ -227,6 +269,7 @@ export class TrainerConfig {
|
||||
|
||||
constructor(trainerType: TrainerType, allowLegendaries?: boolean) {
|
||||
this.trainerType = trainerType;
|
||||
this.trainerAI = new TrainerAI();
|
||||
this.name = Utils.toReadableString(TrainerType[this.getDerivedType()]);
|
||||
this.battleBgm = "battle_trainer";
|
||||
this.mixedBattleBgm = "battle_trainer";
|
||||
@ -550,6 +593,47 @@ export class TrainerConfig {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets random pokemon from the trainers team to instant tera. Uses their specialty types is they have one.
|
||||
* @param count The amount of pokemon to have instant tera
|
||||
* @returns this
|
||||
*/
|
||||
setRandomTeraModifiers(count: () => integer): TrainerConfig {
|
||||
this.genAIFuncs.push((party: EnemyPokemon[]) => {
|
||||
const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
|
||||
for (let t = 0; t < Math.min(count(), party.length); t++) {
|
||||
const randomIndex = Utils.randSeedItem(partyMemberIndexes);
|
||||
partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
|
||||
if (this.specialtyTypes?.length) {
|
||||
party[randomIndex].teraType = Utils.randSeedItem(this.specialtyTypes);
|
||||
}
|
||||
this.trainerAI.setInstantTera(randomIndex);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific pokemon to instant tera
|
||||
* @param index The index within the team to have instant tera
|
||||
* @returns this
|
||||
*/
|
||||
setInstantTera(index: number): TrainerConfig {
|
||||
this.trainerAI.setInstantTera(index);
|
||||
return this;
|
||||
}
|
||||
|
||||
// function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: Type[]): PersistentModifier[] {
|
||||
// const ret: PersistentModifier[] = [];
|
||||
// const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
|
||||
// for (let t = 0; t < Math.min(count, party.length); t++) {
|
||||
// const randomIndex = Utils.randSeedItem(partyMemberIndexes);
|
||||
// partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
|
||||
// ret.push(modifierTypes.TERA_SHARD().generateType([], [ Utils.randSeedItem(types ? types : party[randomIndex].getTypes()) ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct?
|
||||
// }
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
setEventModifierRewardFuncs(...modifierTypeFuncs: (() => ModifierTypeFunc)[]): TrainerConfig {
|
||||
this.eventRewardFuncs = modifierTypeFuncs.map(func => () => {
|
||||
const modifierTypeFunc = func();
|
||||
@ -851,10 +935,7 @@ export class TrainerConfig {
|
||||
this.setHasVoucher(true);
|
||||
this.setBattleBgm("battle_unova_gym");
|
||||
this.setVictoryBgm("victory_gym");
|
||||
this.setGenModifiersFunc(party => {
|
||||
const waveIndex = globalScene.currentBattle.waveIndex;
|
||||
return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : undefined);
|
||||
});
|
||||
this.setRandomTeraModifiers(() => globalScene.currentBattle.waveIndex >= 100 ? 1 : 0);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -910,7 +991,7 @@ export class TrainerConfig {
|
||||
this.setHasVoucher(true);
|
||||
this.setBattleBgm("battle_unova_elite");
|
||||
this.setVictoryBgm("victory_gym");
|
||||
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 1, specialtyTypes.length ? specialtyTypes : undefined));
|
||||
this.setRandomTeraModifiers(() => 1);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1197,16 +1278,6 @@ function getSpeciesFilterRandomPartyMemberFunc(
|
||||
};
|
||||
}
|
||||
|
||||
function getRandomTeraModifiers(party: EnemyPokemon[], count: number, types?: Type[]): PersistentModifier[] {
|
||||
const ret: PersistentModifier[] = [];
|
||||
const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
|
||||
for (let t = 0; t < Math.min(count, party.length); t++) {
|
||||
const randomIndex = Utils.randSeedItem(partyMemberIndexes);
|
||||
partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
|
||||
ret.push(modifierTypes.TERA_SHARD().generateType([], [ Utils.randSeedItem(types ? types : party[randomIndex].getTypes()) ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct?
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
type SignatureSpecies = {
|
||||
[key in string]: (Species | Species[])[];
|
||||
@ -1747,10 +1818,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.RED]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PIKACHU ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 8; // G-Max Pikachu
|
||||
@ -1774,10 +1842,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.KINGDRA ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.AERODACTYL ]))
|
||||
@ -1787,16 +1852,15 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.CHARIZARD ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.type1;
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DRAGONITE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SKARMORY ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CRADILY, Species.ARMALDO ]))
|
||||
@ -1814,10 +1878,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.generateName();
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PELIPPER ], TrainerSlot.TRAINER, true, p => {
|
||||
p.abilityIndex = 1; // Drizzle
|
||||
@ -1840,10 +1901,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.gender = Gender.FEMALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SPIRITOMB ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1853,7 +1911,9 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MILOTIC, Species.ROSERADE, Species.HISUI_ARCANINE ]))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MILOTIC, Species.ROSERADE, Species.HISUI_ARCANINE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.type1;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.TOGEKISS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.setBoss(true, 2);
|
||||
@ -1864,10 +1924,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.gender = Gender.FEMALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.BOUFFALANT, Species.BRAVIARY ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HISUI_LILLIGANT, Species.HISUI_ZOROARK, Species.BASCULEGION ], TrainerSlot.TRAINER, true, p => {
|
||||
@ -1882,16 +1939,15 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CHANDELURE, Species.KROOKODILE, Species.REUNICLUS, Species.CONKELDURR ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CHANDELURE, Species.KROOKODILE, Species.REUNICLUS, Species.CONKELDURR ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.speciesId === Species.KROOKODILE ? Type.DARK : p.species.type1;
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.VOLCARONA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const pokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ pokemon.species.speciesId === Species.KROOKODILE ? pokemon.species.type2 : pokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(pokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.DRUDDIGON ]))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ARCHEOPS ]))
|
||||
@ -1899,7 +1955,9 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.HYDREIGON, Species.ARCHALUDON ]))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.HYDREIGON, Species.ARCHALUDON ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = Type.DRAGON;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.LAPRAS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 1; // G-Max Lapras
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1911,10 +1969,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.gender = Gender.FEMALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ Type.DRAGON ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_kalos_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.HAWLUCHA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1927,6 +1982,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TYRANTRUM, Species.AURORUS ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.abilityIndex = 2; // Rock Head Tyrantrum, Snow Warning Aurorus
|
||||
p.teraType = p.species.speciesId === Species.TYRANTRUM ? Type.DRAGON : Type.ICE;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GOODRA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1938,10 +1994,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.gender = Gender.FEMALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.KUKUI]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_champion_kukui")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LYCANROC ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1965,11 +2018,9 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.INCINEROAR, Species.HISUI_DECIDUEYE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.teraType = p.species.speciesId === Species.INCINEROAR ? Type.DARK : Type.FIGHTING;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[5];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(5),
|
||||
[TrainerType.HAU]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_alola_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.ALOLA_RAICHU ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -1982,6 +2033,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TAPU_LELE, Species.TAPU_BULU ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
p.teraType = p.species.type1;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ZYGARDE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 1; // Zygarde 10% forme, Aura Break
|
||||
@ -1993,10 +2045,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.setBoss(true, 2);
|
||||
p.gender = p.species.speciesId === Species.PRIMARINA ? Gender.FEMALE : Gender.MALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.LEON]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_galar_champion")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AEGISLASH ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -2017,10 +2066,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.gender = Gender.MALE;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[3];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(3),
|
||||
[TrainerType.MUSTARD]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_mustard")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CORVIKNIGHT ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -2033,6 +2079,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
p.teraType = Type.PSYCHIC;
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GALAR_DARMANITAN ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -2050,10 +2097,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.gender = Gender.MALE;
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[2];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(2),
|
||||
[TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_geeta")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GLIMMORA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -2070,11 +2114,9 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KINGAMBIT ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.abilityIndex = 1; // Supreme Overlord
|
||||
p.teraType = Type.FLYING;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[5];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ Type.FLYING ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(5),
|
||||
[TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(false).setMixedBattleBgm("battle_champion_nemona")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LYCANROC ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = 0; // Midday form
|
||||
@ -2086,16 +2128,15 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GHOLDENGO ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ARMAROUGE, Species.CERULEDGE ]))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.ARMAROUGE, Species.CERULEDGE ], TrainerSlot.TRAINER, true, p => {
|
||||
p.teraType = p.species.speciesId === Species.ARMAROUGE ? Type.PSYCHIC : Type.GHOST;
|
||||
}))
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type2 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(true).setMixedBattleBgm("battle_champion_kieran")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.POLIWRATH, Species.POLITOED ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
@ -2117,7 +2158,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.OGERPON ], TrainerSlot.TRAINER, true, p => {
|
||||
p.formIndex = Utils.randSeedInt(4, 4); // Random Ogerpon Tera Mask
|
||||
p.formIndex = Utils.randSeedInt(4); // Random Ogerpon Tera Mask
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) { // Check if Ivy Cudgel is in the moveset, if not, replace the first move with Ivy Cudgel.
|
||||
@ -2129,17 +2170,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.gender = Gender.MALE;
|
||||
p.setBoss(true, 2);
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const starter = party[4];
|
||||
let teraShardType: Type;
|
||||
const pokemonType2 = starter.species.forms[starter.formIndex].type2;
|
||||
if (starter.formIndex === 4 || Utils.isNullOrUndefined(pokemonType2)) {
|
||||
teraShardType = starter.species.type1;
|
||||
} else {
|
||||
teraShardType = pokemonType2;
|
||||
}
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraShardType ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ];
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
|
||||
[TrainerType.RIVAL]: new TrainerConfig((t = TrainerType.RIVAL)).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setStaticParty().setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival").setMixedBattleBgm("battle_rival").setPartyTemplates(trainerPartyTemplates.RIVAL)
|
||||
.setModifierRewardFuncs(() => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE)
|
||||
@ -2162,19 +2193,20 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
.setSpeciesFilter(species => species.baseTotal >= 540),
|
||||
[TrainerType.RIVAL_4]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(1.75).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_2").setMixedBattleBgm("battle_rival_2").setPartyTemplates(trainerPartyTemplates.RIVAL_4)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true,
|
||||
(p => p.abilityIndex = 0)))
|
||||
(p => {
|
||||
p.abilityIndex = 0;
|
||||
p.teraType = p.species.type1;
|
||||
})))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450))
|
||||
.setSpeciesFilter(species => species.baseTotal >= 540)
|
||||
.setGenModifiersFunc(party => {
|
||||
const starter = party[0];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ starter.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; // TODO: is the bang correct?
|
||||
}),
|
||||
.setInstantTera(0),
|
||||
[TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true,
|
||||
p => {
|
||||
p.setBoss(true, 2);
|
||||
p.abilityIndex = 0;
|
||||
p.teraType = p.species.type1;
|
||||
}))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true))
|
||||
.setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450))
|
||||
@ -2185,15 +2217,13 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.shiny = true;
|
||||
p.variant = 1;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const starter = party[0];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ starter.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; //TODO: is the bang correct?
|
||||
}),
|
||||
.setInstantTera(0),
|
||||
[TrainerType.RIVAL_6]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm("final").setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_6)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true,
|
||||
p => {
|
||||
p.setBoss(true, 3);
|
||||
p.abilityIndex = 0;
|
||||
p.teraType = p.species.type1;
|
||||
p.generateAndPopulateMoveset();
|
||||
}))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true,
|
||||
@ -2212,10 +2242,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.formIndex = 1; // Mega Rayquaza
|
||||
p.generateName();
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const starter = party[0];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ starter.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; // TODO: is the bang correct?
|
||||
}),
|
||||
.setInstantTera(0),
|
||||
|
||||
[TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN ], TrainerSlot.TRAINER, true, p => {
|
||||
@ -2713,10 +2740,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
p.generateName();
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[4];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
||||
}),
|
||||
.setInstantTera(4),
|
||||
[TrainerType.PENNY_2]: new TrainerConfig(++t).setName("Cassiopeia").initForEvilTeamLeader("Star Boss", [], true).setMixedBattleBgm("battle_star_boss").setVictoryBgm("victory_team_plasma")
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SYLVEON ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
@ -2749,10 +2773,12 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.generateName();
|
||||
p.pokeball = PokeballType.ULTRA_BALL;
|
||||
}))
|
||||
.setGenModifiersFunc(party => {
|
||||
const teraPokemon = party[0];
|
||||
return [ modifierTypes.TERA_SHARD().generateType([], [ teraPokemon.species.type1 ])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(teraPokemon) as PersistentModifier ]; //TODO: is the bang correct?
|
||||
}),
|
||||
.setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.ZAMAZENTA ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 2);
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
}))
|
||||
.setInstantTera(0),
|
||||
[TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer([], true)
|
||||
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLAYDOL ], TrainerSlot.TRAINER, true, p => {
|
||||
p.setBoss(true, 3);
|
||||
|
@ -44,6 +44,7 @@ export class Arena {
|
||||
public bgm: string;
|
||||
public ignoreAbilities: boolean;
|
||||
public ignoringEffectSource: BattlerIndex | null;
|
||||
public playerTerasUsed: number;
|
||||
/**
|
||||
* Saves the number of times a party pokemon faints during a arena encounter.
|
||||
* {@linkcode globalScene.currentBattle.enemyFaints} is the corresponding faint counter for the enemy (this resets every wave).
|
||||
@ -63,6 +64,7 @@ export class Arena {
|
||||
this.bgm = bgm;
|
||||
this.trainerPool = biomeTrainerPools[biome];
|
||||
this.updatePoolsForTimeOfDay();
|
||||
this.playerTerasUsed = 0;
|
||||
this.playerFaints = playerFaints;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,9 @@ export default class PokemonSpriteSparkleHandler {
|
||||
if (!s.visible || (s.parentContainer instanceof Pokemon && !s.parentContainer.parentContainer)) {
|
||||
continue;
|
||||
}
|
||||
if (!(s.parentContainer instanceof Pokemon) || !(s.parentContainer as Pokemon).isTerastallized) {
|
||||
continue;
|
||||
}
|
||||
const pokemon = s.parentContainer instanceof Pokemon ? s.parentContainer as Pokemon : null;
|
||||
const parent = (pokemon || s).parentContainer;
|
||||
const texture = s.texture;
|
||||
|
@ -52,7 +52,7 @@ import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
||||
import { Type } from "#enums/type";
|
||||
import { getLevelTotalExp } from "#app/data/exp";
|
||||
import { Stat, type PermanentStat, type BattleStat, type EffectiveStat, PERMANENT_STATS, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
||||
import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonIncrementingStatModifier, EvoTrackerModifier, PokemonMultiHitModifier } from "#app/modifier/modifier";
|
||||
import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonIncrementingStatModifier, EvoTrackerModifier, PokemonMultiHitModifier } from "#app/modifier/modifier";
|
||||
import { PokeballType } from "#enums/pokeball";
|
||||
import { Gender } from "#app/data/gender";
|
||||
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
||||
@ -79,7 +79,7 @@ import { DexAttr } from "#app/system/game-data";
|
||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
||||
import { getNatureStatMultiplier } from "#app/data/nature";
|
||||
import type { SpeciesFormChange } from "#app/data/pokemon-forms";
|
||||
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms";
|
||||
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms";
|
||||
import { TerrainType } from "#app/data/terrain";
|
||||
import type { TrainerSlot } from "#app/data/trainer-config";
|
||||
import Overrides from "#app/overrides";
|
||||
@ -163,6 +163,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public pokerus: boolean;
|
||||
public switchOutStatus: boolean;
|
||||
public evoCounter: number;
|
||||
public teraType: Type;
|
||||
public isTerastallized: boolean;
|
||||
public stellarTypesBoosted: Type[];
|
||||
|
||||
public fusionSpecies: PokemonSpecies | null;
|
||||
public fusionFormIndex: number;
|
||||
@ -172,6 +175,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public fusionGender: Gender;
|
||||
public fusionLuck: number;
|
||||
public fusionCustomPokemonData: CustomPokemonData | null;
|
||||
public fusionTeraType: Type;
|
||||
|
||||
private summonDataPrimer: PokemonSummonData | null;
|
||||
|
||||
@ -269,8 +273,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.fusionGender = dataSource.fusionGender;
|
||||
this.fusionLuck = dataSource.fusionLuck;
|
||||
this.fusionCustomPokemonData = dataSource.fusionCustomPokemonData;
|
||||
this.fusionTeraType = dataSource.fusionTeraType;
|
||||
this.usedTMs = dataSource.usedTMs ?? [];
|
||||
this.customPokemonData = new CustomPokemonData(dataSource.customPokemonData);
|
||||
this.teraType = dataSource.teraType;
|
||||
this.isTerastallized = dataSource.isTerastallized;
|
||||
this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? [];
|
||||
} else {
|
||||
this.id = Utils.randSeedInt(4294967296);
|
||||
this.ivs = ivs || Utils.getIvsFromId(this.id);
|
||||
@ -319,6 +327,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
this.luck = (this.shiny ? this.variant + 1 : 0) + (this.fusionShiny ? this.fusionVariant + 1 : 0);
|
||||
this.fusionLuck = this.luck;
|
||||
|
||||
this.teraType = Utils.randSeedItem(this.getTypes(false, false, true));
|
||||
this.isTerastallized = false;
|
||||
this.stellarTypesBoosted = [];
|
||||
}
|
||||
|
||||
this.generateName();
|
||||
@ -355,7 +367,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
const getSprite = (hasShadow?: boolean) => {
|
||||
const ret = globalScene.addPokemonSprite(this, 0, 0, `pkmn__${this.isPlayer() ? "back__" : ""}sub`, undefined, true);
|
||||
ret.setOrigin(0.5, 1);
|
||||
ret.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow, teraColor: getTypeRgb(this.getTeraType()) });
|
||||
ret.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow, teraColor: getTypeRgb(this.getTeraType()), isTerastallized: this.isTerastallized });
|
||||
return ret;
|
||||
};
|
||||
|
||||
@ -723,7 +735,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
updateSpritePipelineData(): void {
|
||||
[ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType()));
|
||||
[ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => {
|
||||
s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType());
|
||||
s.pipelineData["isTerastallized"] = this.isTerastallized;
|
||||
});
|
||||
this.updateInfo(true);
|
||||
}
|
||||
|
||||
@ -1208,6 +1223,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return this.fusionSpecies?.speciesId === species;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@linkcode Pokemon} has is the specified {@linkcode Species} or is fused with it.
|
||||
* @param species the pokemon {@linkcode Species} to check
|
||||
* @returns `true` if the pokemon is the species or is fused with it, `false` otherwise
|
||||
*/
|
||||
hasSpecies(species: Species): boolean {
|
||||
return this.species.speciesId === species || this.fusionSpecies?.speciesId === species;
|
||||
}
|
||||
|
||||
abstract isBoss(): boolean;
|
||||
|
||||
getMoveset(ignoreOverride?: boolean): (PokemonMove | null)[] {
|
||||
@ -1284,9 +1308,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public getTypes(includeTeraType = false, forDefend: boolean = false, ignoreOverride: boolean = false): Type[] {
|
||||
const types: Type[] = [];
|
||||
|
||||
if (includeTeraType) {
|
||||
if (includeTeraType && this.isTerastallized) {
|
||||
const teraType = this.getTeraType();
|
||||
if (teraType !== Type.UNKNOWN) {
|
||||
if (this.isTerastallized && !(forDefend && teraType === Type.STELLAR)) { // Stellar tera uses its original types defensively
|
||||
types.push(teraType);
|
||||
if (forDefend) {
|
||||
return types;
|
||||
@ -1590,23 +1614,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the pokemon's current tera {@linkcode Type}, or `Type.UNKNOWN` if the pokemon is not terastallized
|
||||
* @returns the pokemon's current tera {@linkcode Type}
|
||||
*/
|
||||
public getTeraType(): Type {
|
||||
// I don't think this should be possible anymore, please report if you encounter this. --NightKev
|
||||
if (globalScene === undefined) {
|
||||
console.warn("Pokemon.getTeraType(): Global scene is not defined!");
|
||||
return Type.UNKNOWN;
|
||||
getTeraType(): Type {
|
||||
if (this.hasSpecies(Species.TERAPAGOS)) {
|
||||
return Type.STELLAR;
|
||||
} else if (this.hasSpecies(Species.OGERPON)) {
|
||||
const ogerponForm = this.species.speciesId === Species.OGERPON ? this.formIndex : this.fusionFormIndex;
|
||||
switch (ogerponForm) {
|
||||
case 0:
|
||||
case 4:
|
||||
return Type.GRASS;
|
||||
case 1:
|
||||
case 5:
|
||||
return Type.WATER;
|
||||
case 2:
|
||||
case 6:
|
||||
return Type.FIRE;
|
||||
case 3:
|
||||
case 7:
|
||||
return Type.ROCK;
|
||||
}
|
||||
} else if (this.hasSpecies(Species.SHEDINJA)) {
|
||||
return Type.BUG;
|
||||
}
|
||||
const teraModifier = globalScene.findModifier(m =>
|
||||
m instanceof TerastallizeModifier
|
||||
&& m.pokemonId === this.id
|
||||
&& m.getBattlesLeft() > 0, this.isPlayer()) as TerastallizeModifier;
|
||||
return teraModifier?.teraType ?? Type.UNKNOWN;
|
||||
}
|
||||
|
||||
public isTerastallized(): boolean {
|
||||
return this.getTeraType() !== Type.UNKNOWN;
|
||||
return this.teraType;
|
||||
}
|
||||
|
||||
public isGrounded(): boolean {
|
||||
@ -1748,7 +1780,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
*/
|
||||
getAttackTypeEffectiveness(moveType: Type, source?: Pokemon, ignoreStrongWinds: boolean = false, simulated: boolean = true, move?: Move): TypeDamageMultiplier {
|
||||
if (moveType === Type.STELLAR) {
|
||||
return this.isTerastallized() ? 2 : 1;
|
||||
return this.isTerastallized ? 2 : 1;
|
||||
}
|
||||
const types = this.getTypes(true, true);
|
||||
const arena = globalScene.arena;
|
||||
@ -2785,11 +2817,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
const matchesSourceType = sourceTypes.includes(moveType);
|
||||
/** A damage multiplier for when the attack is of the attacker's type and/or Tera type. */
|
||||
const stabMultiplier = new Utils.NumberHolder(1);
|
||||
if (matchesSourceType) {
|
||||
stabMultiplier.value += 0.5;
|
||||
}
|
||||
applyMoveAttrs(CombinedPledgeStabBoostAttr, source, this, move, stabMultiplier);
|
||||
if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === moveType) {
|
||||
if (matchesSourceType && moveType !== Type.STELLAR) {
|
||||
stabMultiplier.value += 0.5;
|
||||
}
|
||||
|
||||
@ -2797,6 +2825,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
applyAbAttrs(StabBoostAbAttr, source, null, simulated, stabMultiplier);
|
||||
}
|
||||
|
||||
applyMoveAttrs(CombinedPledgeStabBoostAttr, source, this, move, stabMultiplier);
|
||||
|
||||
if (source.isTerastallized && sourceTeraType === moveType && moveType !== Type.STELLAR) {
|
||||
stabMultiplier.value += 0.5;
|
||||
}
|
||||
|
||||
if (source.isTerastallized && source.teraType === Type.STELLAR && (!source.stellarTypesBoosted.includes(moveType) || source.hasSpecies(Species.TERAPAGOS))) {
|
||||
if (matchesSourceType) {
|
||||
stabMultiplier.value += 0.5;
|
||||
} else {
|
||||
stabMultiplier.value += 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
stabMultiplier.value = Math.min(stabMultiplier.value, 2.25);
|
||||
|
||||
/** Halves damage if the attacker is using a physical attack while burned */
|
||||
@ -3837,6 +3879,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
}
|
||||
|
||||
resetTera(): void {
|
||||
const wasTerastallized = this.isTerastallized;
|
||||
this.isTerastallized = false;
|
||||
this.stellarTypesBoosted = [];
|
||||
if (wasTerastallized) {
|
||||
this.updateSpritePipelineData();
|
||||
globalScene.triggerPokemonFormChange(this, SpeciesFormChangeLapseTeraTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
resetTurnData(): void {
|
||||
this.turnData = new PokemonTurnData();
|
||||
}
|
||||
@ -4600,6 +4652,7 @@ export class PlayerPokemon extends Pokemon {
|
||||
newPokemon.fusionVariant = this.fusionVariant;
|
||||
newPokemon.fusionGender = this.fusionGender;
|
||||
newPokemon.fusionLuck = this.fusionLuck;
|
||||
newPokemon.fusionTeraType = this.teraType;
|
||||
newPokemon.usedTMs = this.usedTMs;
|
||||
|
||||
globalScene.getPlayerParty().push(newPokemon);
|
||||
@ -4751,6 +4804,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
public aiType: AiType;
|
||||
public bossSegments: number;
|
||||
public bossSegmentIndex: number;
|
||||
public initialTeamIndex: number;
|
||||
/** To indicate if the instance was populated with a dataSource -> e.g. loaded & populated from session data */
|
||||
public readonly isPopulatedFromDataSource: boolean;
|
||||
|
||||
@ -4760,6 +4814,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
undefined, dataSource ? dataSource.nature : undefined, dataSource);
|
||||
|
||||
this.trainerSlot = trainerSlot;
|
||||
this.initialTeamIndex = globalScene.currentBattle?.enemyParty.length ?? 0;
|
||||
this.isPopulatedFromDataSource = !!dataSource; // if a dataSource is provided, then it was populated from dataSource
|
||||
if (boss) {
|
||||
this.setBoss(boss, dataSource?.bossSegments);
|
||||
|
@ -11,7 +11,8 @@ import {
|
||||
TrainerSlot,
|
||||
trainerConfigs,
|
||||
trainerPartyTemplates,
|
||||
signatureSpecies
|
||||
signatureSpecies,
|
||||
TeraAIMode
|
||||
} from "#app/data/trainer-config";
|
||||
import type { EnemyPokemon } from "#app/field/pokemon";
|
||||
import * as Utils from "#app/utils";
|
||||
@ -36,6 +37,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
public partyTemplateIndex: number;
|
||||
public name: string;
|
||||
public partnerName: string;
|
||||
public originalIndexes: { [key: number]: number } = {};
|
||||
|
||||
constructor(trainerType: TrainerType, variant: TrainerVariant, partyTemplateIndex?: number, name?: string, partnerName?: string, trainerConfigOverride?: TrainerConfig) {
|
||||
super(globalScene, -72, 80);
|
||||
@ -546,6 +548,13 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
return [];
|
||||
}
|
||||
|
||||
genAI(party: EnemyPokemon[]) {
|
||||
if (this.config.genAIFuncs) {
|
||||
this.config.genAIFuncs.forEach(f => f(party));
|
||||
}
|
||||
console.log("Generated AI funcs");
|
||||
}
|
||||
|
||||
loadAssets(): Promise<void> {
|
||||
return this.config.loadAssets(this.variant);
|
||||
}
|
||||
@ -667,4 +676,13 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
shouldTera(pokemon: EnemyPokemon): boolean {
|
||||
if (this.config.trainerAI.teraMode === TeraAIMode.INSTANT_TERA) {
|
||||
if (!pokemon.isTerastallized && this.config.trainerAI.instantTeras.includes(pokemon.initialTeamIndex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ export class LoadingScene extends SceneBase {
|
||||
this.loadImage("icon_tera", "ui");
|
||||
this.loadImage("type_tera", "ui");
|
||||
this.loadAtlas("type_bgs", "ui");
|
||||
this.loadAtlas("button_tera", "ui");
|
||||
this.loadImage("mystery_egg", "ui");
|
||||
this.loadImage("normal_memory", "ui");
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { Type } from "#enums/type";
|
||||
import type { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier, CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier";
|
||||
import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerrastalizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier, TempExtraModifierModifier, CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier";
|
||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||
import Overrides from "#app/overrides";
|
||||
import { Unlockables } from "#app/system/unlockables";
|
||||
@ -19,7 +19,7 @@ import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system
|
||||
import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
||||
import PartyUiHandler from "#app/ui/party-ui-handler";
|
||||
import { getModifierTierTextTint } from "#app/ui/text";
|
||||
import { formatMoney, getEnumKeys, getEnumValues, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils";
|
||||
import { formatMoney, getEnumKeys, getEnumValues, isNullOrUndefined, NumberHolder, padInt, randSeedInt } from "#app/utils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
@ -275,6 +275,36 @@ export class PokemonHeldItemModifierType extends PokemonModifierType {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class TerastallizeModifierType extends PokemonModifierType {
|
||||
private teraType: Type;
|
||||
|
||||
constructor(teraType: Type) {
|
||||
super("", `${Type[teraType].toLowerCase()}_tera_shard`, (type, args) => new TerrastalizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType),
|
||||
(pokemon: PlayerPokemon) => {
|
||||
if ([ pokemon.species.speciesId, pokemon.fusionSpecies?.speciesId ].filter(s => s === Species.TERAPAGOS || s === Species.OGERPON || s === Species.SHEDINJA).length > 0) {
|
||||
return PartyUiHandler.NoEffectMessage;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
"tera_shard");
|
||||
|
||||
this.teraType = teraType;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("modifierType:ModifierType.TerastallizeModifierType.name", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return i18next.t("modifierType:ModifierType.TerastallizeModifierType.description", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
|
||||
}
|
||||
|
||||
getPregenArgs(): any[] {
|
||||
return [ this.teraType ];
|
||||
}
|
||||
}
|
||||
|
||||
export class PokemonHpRestoreModifierType extends PokemonModifierType {
|
||||
protected restorePoints: number;
|
||||
protected restorePercent: number;
|
||||
@ -1192,28 +1222,6 @@ class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
export class TerastallizeModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
||||
private teraType: Type;
|
||||
|
||||
constructor(teraType: Type) {
|
||||
super("", `${Type[teraType].toLowerCase()}_tera_shard`, (type, args) => new TerastallizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType), "tera_shard");
|
||||
|
||||
this.teraType = teraType;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("modifierType:ModifierType.TerastallizeModifierType.name", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return i18next.t("modifierType:ModifierType.TerastallizeModifierType.description", { teraType: i18next.t(`pokemonInfo:Type.${Type[this.teraType]}`) });
|
||||
}
|
||||
|
||||
getPregenArgs(): any[] {
|
||||
return [ this.teraType ];
|
||||
}
|
||||
}
|
||||
|
||||
export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemModifierType {
|
||||
private chancePercent: number;
|
||||
|
||||
@ -1469,14 +1477,21 @@ export const modifierTypes = {
|
||||
if (!globalScene.getModifiers(TerastallizeAccessModifier).length) {
|
||||
return null;
|
||||
}
|
||||
let type: Type;
|
||||
if (!randSeedInt(3)) {
|
||||
const partyMemberTypes = party.map(p => p.getTypes(false, false, true)).flat();
|
||||
type = randSeedItem(partyMemberTypes);
|
||||
} else {
|
||||
type = randSeedInt(64) ? randSeedInt(18) as Type : Type.STELLAR;
|
||||
const teraTypes: Type[] = [];
|
||||
party.forEach(p => {
|
||||
if (!(p.hasSpecies(Species.TERAPAGOS) || p.hasSpecies(Species.OGERPON) || p.hasSpecies(Species.SHEDINJA))) {
|
||||
teraTypes.push(p.teraType);
|
||||
}
|
||||
});
|
||||
let excludedType = Type.UNKNOWN;
|
||||
if (teraTypes.length > 0 && teraTypes.filter(t => t === teraTypes[0]).length === teraTypes.length) {
|
||||
excludedType = teraTypes[0];
|
||||
}
|
||||
return new TerastallizeModifierType(type);
|
||||
let shardType = randSeedInt(64) ? randSeedInt(18) as Type : Type.STELLAR;
|
||||
while (shardType === excludedType) {
|
||||
shardType = randSeedInt(64) ? randSeedInt(18) as Type : Type.STELLAR;
|
||||
}
|
||||
return new TerastallizeModifierType(shardType);
|
||||
}),
|
||||
|
||||
BERRY: () => new ModifierTypeGenerator((_party: Pokemon[], pregenArgs?: any[]) => {
|
||||
@ -1719,7 +1734,7 @@ const modifierPool: ModifierPool = {
|
||||
return Math.min(Math.ceil(highestPartyLevel / 20), 4);
|
||||
}, 4),
|
||||
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3),
|
||||
new WeightedModifierType(modifierTypes.TERA_SHARD, 1),
|
||||
new WeightedModifierType(modifierTypes.TERA_SHARD, (party: Pokemon[]) => party.filter(p => !(p.hasSpecies(Species.TERAPAGOS) || p.hasSpecies(Species.OGERPON) || p.hasSpecies(Species.SHEDINJA))).length > 0 ? 1 : 0),
|
||||
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => {
|
||||
if (party.filter(p => !p.fusionSpecies).length > 1) {
|
||||
if (globalScene.gameMode.isSplicedOnly) {
|
||||
|
@ -3,16 +3,16 @@ import { getBerryEffectFunc, getBerryPredicate } from "#app/data/berry";
|
||||
import { getLevelTotalExp } from "#app/data/exp";
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
|
||||
import { type FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms";
|
||||
import { type FormChangeItem, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
|
||||
import { getStatusEffectHealText } from "#app/data/status-effect";
|
||||
import Pokemon, { type PlayerPokemon } from "#app/field/pokemon";
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import Pokemon from "#app/field/pokemon";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import Overrides from "#app/overrides";
|
||||
import { EvolutionPhase } from "#app/phases/evolution-phase";
|
||||
import { LearnMovePhase, LearnMoveType } from "#app/phases/learn-move-phase";
|
||||
import { LevelUpPhase } from "#app/phases/level-up-phase";
|
||||
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||
import { achvs } from "#app/system/achv";
|
||||
import type { VoucherType } from "#app/system/voucher";
|
||||
import { Command } from "#app/ui/command-ui-handler";
|
||||
import { addTextObject, TextStyle } from "#app/ui/text";
|
||||
@ -25,7 +25,7 @@ import type { PokeballType } from "#enums/pokeball";
|
||||
import { Species } from "#enums/species";
|
||||
import { type PermanentStat, type TempBattleStat, BATTLE_STATS, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { Type } from "#enums/type";
|
||||
import type { Type } from "#enums/type";
|
||||
import i18next from "i18next";
|
||||
import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type PokemonBaseStatTotalModifierType, type PokemonExpBoosterModifierType, type PokemonFriendshipBoosterModifierType, type PokemonMoveAccuracyBoosterModifierType, type PokemonMultiHitModifierType, type TerastallizeModifierType, type TmModifierType, getModifierType, ModifierPoolType, ModifierTypeGenerator, modifierTypes, PokemonHeldItemModifierType } from "./modifier-type";
|
||||
import { Color, ShadowColor } from "#enums/color";
|
||||
@ -786,72 +786,6 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi
|
||||
}
|
||||
}
|
||||
|
||||
export class TerastallizeModifier extends LapsingPokemonHeldItemModifier {
|
||||
public override type: TerastallizeModifierType;
|
||||
public teraType: Type;
|
||||
public isTransferable: boolean = false;
|
||||
|
||||
constructor(type: TerastallizeModifierType, pokemonId: number, teraType: Type, battlesLeft?: number, stackCount?: number) {
|
||||
super(type, pokemonId, battlesLeft || 10, stackCount);
|
||||
|
||||
this.teraType = teraType;
|
||||
}
|
||||
|
||||
matchType(modifier: Modifier): boolean {
|
||||
if (modifier instanceof TerastallizeModifier && modifier.teraType === this.teraType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clone(): TerastallizeModifier {
|
||||
return new TerastallizeModifier(this.type, this.pokemonId, this.teraType, this.battlesLeft, this.stackCount);
|
||||
}
|
||||
|
||||
getArgs(): any[] {
|
||||
return [ this.pokemonId, this.teraType, this.battlesLeft ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the {@linkcode TerastallizeModifier} to the specified {@linkcode Pokemon}.
|
||||
* @param pokemon the {@linkcode Pokemon} to be terastallized
|
||||
* @returns always `true`
|
||||
*/
|
||||
override apply(pokemon: Pokemon): boolean {
|
||||
if (pokemon.isPlayer()) {
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeTeraTrigger);
|
||||
globalScene.validateAchv(achvs.TERASTALLIZE);
|
||||
if (this.teraType === Type.STELLAR) {
|
||||
globalScene.validateAchv(achvs.STELLAR_TERASTALLIZE);
|
||||
}
|
||||
}
|
||||
pokemon.updateSpritePipelineData();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers {@linkcode LapsingPokemonHeldItemModifier.lapse} and if it returns `0` a form change is triggered.
|
||||
* @param pokemon THe {@linkcode Pokemon} to be terastallized
|
||||
* @returns the result of {@linkcode LapsingPokemonHeldItemModifier.lapse}
|
||||
*/
|
||||
public override lapse(pokemon: Pokemon): boolean {
|
||||
const ret = super.lapse(pokemon);
|
||||
if (!ret) {
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeLapseTeraTrigger);
|
||||
pokemon.updateSpritePipelineData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
getScoreMultiplier(): number {
|
||||
return 1.25;
|
||||
}
|
||||
|
||||
getMaxHeldItemCount(pokemon: Pokemon): number {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifier used for held items, specifically vitamins like Carbos, Hp Up, etc., that
|
||||
* increase the value of a given {@linkcode PermanentStat}.
|
||||
@ -2022,6 +1956,36 @@ export abstract class ConsumablePokemonModifier extends ConsumableModifier {
|
||||
}
|
||||
}
|
||||
|
||||
export class TerrastalizeModifier extends ConsumablePokemonModifier {
|
||||
public override type: TerastallizeModifierType;
|
||||
public teraType: Type;
|
||||
|
||||
constructor(type: TerastallizeModifierType, pokemonId: number, teraType: Type) {
|
||||
super(type, pokemonId);
|
||||
|
||||
this.teraType = teraType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if {@linkcode TerrastalizeModifier} should be applied
|
||||
* @param playerPokemon The {@linkcode PlayerPokemon} that consumes the item
|
||||
* @returns `true` if the {@linkcode TerrastalizeModifier} should be applied
|
||||
*/
|
||||
override shouldApply(playerPokemon?: PlayerPokemon): boolean {
|
||||
return super.shouldApply(playerPokemon) && [ playerPokemon?.species.speciesId, playerPokemon?.fusionSpecies?.speciesId ].filter(s => s === Species.TERAPAGOS || s === Species.OGERPON || s === Species.SHEDINJA).length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies {@linkcode TerrastalizeModifier}
|
||||
* @param pokemon The {@linkcode PlayerPokemon} that consumes the item
|
||||
* @returns `true` if hp was restored
|
||||
*/
|
||||
override apply(pokemon: Pokemon): boolean {
|
||||
pokemon.teraType = this.teraType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
|
||||
private restorePoints: number;
|
||||
private restorePercent: number;
|
||||
|
@ -118,6 +118,7 @@ export class CommandPhase extends FieldPhase {
|
||||
let success: boolean = false;
|
||||
|
||||
switch (command) {
|
||||
case Command.TERA:
|
||||
case Command.FIGHT:
|
||||
let useStruggle = false;
|
||||
const turnMove: TurnMove | undefined = (args.length === 2 ? (args[1] as TurnMove) : undefined);
|
||||
@ -137,6 +138,7 @@ export class CommandPhase extends FieldPhase {
|
||||
}
|
||||
|
||||
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
|
||||
const preTurnCommand: TurnCommand = { command: command, targets: [ this.fieldIndex ], skip: command === Command.FIGHT };
|
||||
const moveTargets: MoveTargetSet = turnMove === undefined ? getMoveTargets(playerPokemon, moveId) : { targets: turnMove.targets, multiple: turnMove.targets.length > 1 };
|
||||
if (!moveId) {
|
||||
turnCommand.targets = [ this.fieldIndex ];
|
||||
@ -152,6 +154,7 @@ export class CommandPhase extends FieldPhase {
|
||||
} else {
|
||||
globalScene.unshiftPhase(new SelectTargetPhase(this.fieldIndex));
|
||||
}
|
||||
globalScene.currentBattle.preTurnCommands[this.fieldIndex] = preTurnCommand;
|
||||
globalScene.currentBattle.turnCommands[this.fieldIndex] = turnCommand;
|
||||
success = true;
|
||||
} else if (cursor < playerPokemon.getMoveset().length) {
|
||||
|
@ -81,6 +81,10 @@ export class EnemyCommandPhase extends FieldPhase {
|
||||
/** Select a move to use (and a target to use it against, if applicable) */
|
||||
const nextMove = enemyPokemon.getNextMove();
|
||||
|
||||
if (trainer && trainer.shouldTera(enemyPokemon)) {
|
||||
globalScene.currentBattle.preTurnCommands[this.fieldIndex + BattlerIndex.ENEMY] = { command: Command.TERA };
|
||||
}
|
||||
|
||||
globalScene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
|
||||
{ command: Command.FIGHT, move: nextMove, skip: this.skipTurn };
|
||||
|
||||
|
@ -116,7 +116,7 @@ export class EvolutionPhase extends Phase {
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()), isTerastallized: this.pokemon.isTerastallized });
|
||||
sprite.setPipelineData("ignoreTimeTint", true);
|
||||
sprite.setPipelineData("spriteKey", this.pokemon.getSpriteKey());
|
||||
sprite.setPipelineData("shiny", this.pokemon.shiny);
|
||||
|
@ -108,6 +108,8 @@ export class FaintPhase extends PokemonPhase {
|
||||
globalScene.queueMessage(i18next.t("battle:fainted", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, true);
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
|
||||
pokemon.resetTera();
|
||||
|
||||
if (pokemon.turnData?.attacksReceived?.length) {
|
||||
const lastAttack = pokemon.turnData.attacksReceived[0];
|
||||
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, globalScene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct?
|
||||
|
@ -450,6 +450,12 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
target.lapseTag(BattlerTagType.SUBSTITUTE);
|
||||
}
|
||||
});
|
||||
|
||||
const moveType = user.getMoveType(move, true);
|
||||
if (move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) {
|
||||
user.stellarTypesBoosted.push(moveType);
|
||||
}
|
||||
|
||||
this.end();
|
||||
});
|
||||
});
|
||||
|
@ -36,5 +36,6 @@ export class PartyHealPhase extends BattlePhase {
|
||||
globalScene.ui.fadeIn(500).then(() => this.end());
|
||||
});
|
||||
});
|
||||
globalScene.arena.playerTerasUsed = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { SemiInvulnerableTag } from "#app/data/battler-tags";
|
||||
import type { SpeciesFormChange } from "#app/data/pokemon-forms";
|
||||
import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms";
|
||||
import { getSpeciesFormChangeMessage, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
import { BattleSpec } from "#app/enums/battle-spec";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
@ -11,6 +11,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { BattlePhase } from "./battle-phase";
|
||||
import { MovePhase } from "./move-phase";
|
||||
import { PokemonHealPhase } from "./pokemon-heal-phase";
|
||||
import { applyAbAttrs, PostTeraFormChangeStatChangeAbAttr } from "#app/data/ability";
|
||||
|
||||
export class QuietFormChangePhase extends BattlePhase {
|
||||
protected pokemon: Pokemon;
|
||||
@ -51,7 +52,7 @@ export class QuietFormChangePhase extends BattlePhase {
|
||||
} catch (err: unknown) {
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) });
|
||||
sprite.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()), isTerastallized: this.pokemon.isTerastallized });
|
||||
[ "spriteColors", "fusionSpriteColors" ].map(k => {
|
||||
if (this.pokemon.summonData?.speciesForm) {
|
||||
k += "Base";
|
||||
@ -145,6 +146,9 @@ export class QuietFormChangePhase extends BattlePhase {
|
||||
movePhase.cancel();
|
||||
}
|
||||
}
|
||||
if (this.formChange.trigger instanceof SpeciesFormChangeTeraTrigger) {
|
||||
applyAbAttrs(PostTeraFormChangeStatChangeAbAttr, this.pokemon, null);
|
||||
}
|
||||
|
||||
super.end();
|
||||
}
|
||||
|
51
src/phases/tera-phase.ts
Normal file
51
src/phases/tera-phase.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { BattlePhase } from "./battle-phase";
|
||||
import i18next from "i18next";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { Type } from "#app/enums/type";
|
||||
import { achvs } from "#app/system/achv";
|
||||
import { SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms";
|
||||
import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims";
|
||||
|
||||
export class TeraPhase extends BattlePhase {
|
||||
public pokemon: Pokemon;
|
||||
|
||||
constructor(pokemon: Pokemon) {
|
||||
super();
|
||||
|
||||
this.pokemon = pokemon;
|
||||
}
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
|
||||
console.log(this.pokemon.name, "terastallized to", Type[this.pokemon.teraType].toString());
|
||||
|
||||
globalScene.queueMessage(i18next.t("battle:pokemonTerastallized", { pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), type: i18next.t(`pokemonInfo:Type.${Type[this.pokemon.teraType]}`) }));
|
||||
new CommonBattleAnim(CommonAnim.TERASTALLIZE, this.pokemon).play(false, () => {
|
||||
this.end();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
end() {
|
||||
this.pokemon.isTerastallized = true;
|
||||
this.pokemon.updateSpritePipelineData();
|
||||
|
||||
if (this.pokemon.isPlayer()) {
|
||||
globalScene.arena.playerTerasUsed += 1;
|
||||
}
|
||||
|
||||
globalScene.triggerPokemonFormChange(this.pokemon, SpeciesFormChangeTeraTrigger);
|
||||
|
||||
if (this.pokemon.isPlayer()) {
|
||||
globalScene.validateAchv(achvs.TERASTALLIZE);
|
||||
if (this.pokemon.teraType === Type.STELLAR) {
|
||||
globalScene.validateAchv(achvs.STELLAR_TERASTALLIZE);
|
||||
}
|
||||
}
|
||||
|
||||
super.end();
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import { BattlerIndex } from "#app/battle";
|
||||
import { TrickRoomTag } from "#app/data/arena-tag";
|
||||
import { SwitchType } from "#enums/switch-type";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { TeraPhase } from "./tera-phase";
|
||||
|
||||
export class TurnStartPhase extends FieldPhase {
|
||||
constructor() {
|
||||
@ -139,6 +140,20 @@ export class TurnStartPhase extends FieldPhase {
|
||||
|
||||
let orderIndex = 0;
|
||||
|
||||
for (const o of this.getSpeedOrder()) {
|
||||
const pokemon = field[o];
|
||||
const preTurnCommand = globalScene.currentBattle.preTurnCommands[o];
|
||||
|
||||
if (preTurnCommand?.skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (preTurnCommand?.command) {
|
||||
case Command.TERA:
|
||||
globalScene.pushPhase(new TeraPhase(pokemon));
|
||||
}
|
||||
}
|
||||
|
||||
for (const o of moveOrder) {
|
||||
|
||||
const pokemon = field[o];
|
||||
|
@ -351,7 +351,7 @@ export default class SpritePipeline extends FieldSpritePipeline {
|
||||
|
||||
const data = sprite.pipelineData;
|
||||
const tone = data["tone"] as number[];
|
||||
const teraColor = data["teraColor"] as number[] ?? [ 0, 0, 0 ];
|
||||
const teraColor = (data["isTerastallized"] as boolean) ? (data["teraColor"] as number[] ?? [ 0, 0, 0 ]) : [ 0, 0, 0 ];
|
||||
const hasShadow = data["hasShadow"] as boolean;
|
||||
const yShadowOffset = data["yShadowOffset"] as number;
|
||||
const ignoreFieldPos = data["ignoreFieldPos"] as boolean;
|
||||
|
@ -10,12 +10,14 @@ export default class ArenaData {
|
||||
public weather: Weather | null;
|
||||
public terrain: Terrain | null;
|
||||
public tags: ArenaTag[];
|
||||
public playerTerasUsed: number;
|
||||
|
||||
constructor(source: Arena | any) {
|
||||
const sourceArena = source instanceof Arena ? source as Arena : null;
|
||||
this.biome = sourceArena ? sourceArena.biomeType : source.biome;
|
||||
this.weather = sourceArena ? sourceArena.weather : source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : null;
|
||||
this.terrain = sourceArena ? sourceArena.terrain : source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : null;
|
||||
this.playerTerasUsed = (sourceArena ? sourceArena.playerTerasUsed : source.playerTerasUsed) ?? 0;
|
||||
this.tags = [];
|
||||
|
||||
if (source.tags) {
|
||||
|
@ -1087,6 +1087,8 @@ export class GameData {
|
||||
globalScene.arena.terrain = sessionData.arena.terrain;
|
||||
globalScene.arena.eventTarget.dispatchEvent(new TerrainChangedEvent(TerrainType.NONE, globalScene.arena.terrain?.terrainType!, globalScene.arena.terrain?.turnsLeft!)); // TODO: is this bang correct?
|
||||
|
||||
globalScene.arena.playerTerasUsed = sessionData.arena.playerTerasUsed;
|
||||
|
||||
globalScene.arena.tags = sessionData.arena.tags;
|
||||
if (globalScene.arena.tags) {
|
||||
for (const tag of globalScene.arena.tags) {
|
||||
|
@ -13,6 +13,7 @@ import type { Biome } from "#enums/biome";
|
||||
import { Moves } from "#enums/moves";
|
||||
import type { Species } from "#enums/species";
|
||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||
import type { Type } from "#app/enums/type";
|
||||
|
||||
export default class PokemonData {
|
||||
public id: number;
|
||||
@ -45,6 +46,9 @@ export default class PokemonData {
|
||||
public pokerus: boolean;
|
||||
public usedTMs: Moves[];
|
||||
public evoCounter: number;
|
||||
public teraType: Type;
|
||||
public isTerastallized: boolean;
|
||||
public stellarTypesBoosted: Type[];
|
||||
|
||||
public fusionSpecies: Species;
|
||||
public fusionFormIndex: number;
|
||||
@ -53,6 +57,7 @@ export default class PokemonData {
|
||||
public fusionVariant: Variant;
|
||||
public fusionGender: Gender;
|
||||
public fusionLuck: number;
|
||||
public fusionTeraType: Type;
|
||||
|
||||
public boss: boolean;
|
||||
public bossSegments?: number;
|
||||
@ -103,6 +108,9 @@ export default class PokemonData {
|
||||
this.evoCounter = source.evoCounter ?? 0;
|
||||
}
|
||||
this.pokerus = !!source.pokerus;
|
||||
this.teraType = source.teraType as Type;
|
||||
this.isTerastallized = source.isTerastallized || false;
|
||||
this.stellarTypesBoosted = source.stellarTypesBoosted || [];
|
||||
|
||||
this.fusionSpecies = sourcePokemon ? sourcePokemon.fusionSpecies?.speciesId : source.fusionSpecies;
|
||||
this.fusionFormIndex = source.fusionFormIndex;
|
||||
@ -112,6 +120,7 @@ export default class PokemonData {
|
||||
this.fusionGender = source.fusionGender;
|
||||
this.fusionLuck = source.fusionLuck !== undefined ? source.fusionLuck : (source.fusionShiny ? source.fusionVariant + 1 : 0);
|
||||
this.fusionCustomPokemonData = new CustomPokemonData(source.fusionCustomPokemonData);
|
||||
this.fusionTeraType = (source.fusionTeraType ?? 0) as Type;
|
||||
this.usedTMs = source.usedTMs ?? [];
|
||||
|
||||
this.customPokemonData = new CustomPokemonData(source.customPokemonData);
|
||||
|
@ -7,6 +7,9 @@ import * as v1_0_4 from "./versions/v1_0_4";
|
||||
// --- v1.1.0 PATCHES --- //
|
||||
import * as v1_1_0 from "./versions/v1_1_0";
|
||||
|
||||
// --- v1.7.0 PATCHES --- //
|
||||
import * as v1_7_0 from "./versions/v1_7_0";
|
||||
|
||||
const LATEST_VERSION = version.split(".").map(value => parseInt(value));
|
||||
|
||||
/**
|
||||
@ -138,6 +141,10 @@ class SessionVersionConverter extends VersionConverter {
|
||||
console.log("Applying v1.1.0 session data migration!");
|
||||
this.callMigrators(data, v1_1_0.sessionMigrators);
|
||||
}
|
||||
if (curMinor < 7) {
|
||||
console.log("Applying v1.7.0 session data migration!");
|
||||
this.callMigrators(data, v1_7_0.sessionMigrators);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Session data successfully migrated to v${version}!`);
|
||||
@ -164,6 +171,10 @@ class SystemVersionConverter extends VersionConverter {
|
||||
console.log("Applying v1.1.0 system data migraton!");
|
||||
this.callMigrators(data, v1_1_0.systemMigrators);
|
||||
}
|
||||
if (curMinor < 7) {
|
||||
console.log("Applying v1.7.0 session data migration!");
|
||||
this.callMigrators(data, v1_7_0.systemMigrators);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`System data successfully migrated to v${version}!`);
|
||||
@ -190,6 +201,10 @@ class SettingsVersionConverter extends VersionConverter {
|
||||
console.log("Applying v1.1.0 settings data migraton!");
|
||||
this.callMigrators(data, v1_1_0.settingsMigrators);
|
||||
}
|
||||
if (curMinor < 7) {
|
||||
console.log("Applying v1.7.0 session data migration!");
|
||||
this.callMigrators(data, v1_7_0.settingsMigrators);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`System data successfully migrated to v${version}!`);
|
||||
|
49
src/system/version_migration/versions/v1_7_0.ts
Normal file
49
src/system/version_migration/versions/v1_7_0.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||
import type { SessionSaveData } from "#app/system/game-data";
|
||||
import * as Utils from "#app/utils";
|
||||
|
||||
export const systemMigrators = [] as const;
|
||||
|
||||
export const settingsMigrators = [] as const;
|
||||
|
||||
export const sessionMigrators = [
|
||||
function migrateTera(data: SessionSaveData) {
|
||||
for (let i = 0; i < data.modifiers.length;) {
|
||||
if (data.modifiers[i].className === "TerastallizeModifier") {
|
||||
data.party.forEach((p) => {
|
||||
if (p.id === data.modifiers[i].args[0]) {
|
||||
p.teraType = data.modifiers[i].args[1];
|
||||
}
|
||||
});
|
||||
data.modifiers.splice(i, 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < data.enemyModifiers.length;) {
|
||||
if (data.enemyModifiers[i].className === "TerastallizeModifier") {
|
||||
data.enemyParty.forEach((p) => {
|
||||
if (p.id === data.enemyModifiers[i].args[0]) {
|
||||
p.teraType = data.enemyModifiers[i].args[1];
|
||||
}
|
||||
});
|
||||
data.enemyModifiers.splice(i, 1);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
data.party.forEach(p => {
|
||||
if (Utils.isNullOrUndefined(p.teraType)) {
|
||||
p.teraType = getPokemonSpeciesForm(p.species, p.formIndex).type1;
|
||||
}
|
||||
});
|
||||
|
||||
data.enemyParty.forEach(p => {
|
||||
if (Utils.isNullOrUndefined(p.teraType)) {
|
||||
p.teraType = getPokemonSpeciesForm(p.species, p.formIndex).type1;
|
||||
}
|
||||
});
|
||||
}
|
||||
] as const;
|
@ -11,7 +11,7 @@ import { Species } from "#enums/species";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
|
||||
describe("Abilities - Libero", () => {
|
||||
@ -258,7 +258,7 @@ describe("Abilities - Libero", () => {
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
|
||||
leadPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
@ -11,7 +11,7 @@ import { Species } from "#enums/species";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
|
||||
describe("Abilities - Protean", () => {
|
||||
@ -258,7 +258,7 @@ describe("Abilities - Protean", () => {
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true);
|
||||
leadPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
@ -6,7 +6,6 @@ import { Abilities } from "#app/enums/abilities";
|
||||
import { Moves } from "#app/enums/moves";
|
||||
import { Species } from "#app/enums/species";
|
||||
import * as Messages from "#app/messages";
|
||||
import { TerastallizeModifier, overrideHeldItems } from "#app/modifier/modifier";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
@ -15,15 +14,14 @@ function testMoveEffectiveness(game: GameManager, move: Moves, targetSpecies: Sp
|
||||
expected: number, targetAbility: Abilities = Abilities.BALL_FETCH, teraType?: Type): void {
|
||||
// Suppress getPokemonNameWithAffix because it calls on a null battle spec
|
||||
vi.spyOn(Messages, "getPokemonNameWithAffix").mockReturnValue("");
|
||||
game.override
|
||||
.enemyAbility(targetAbility)
|
||||
.enemyHeldItems([{ name:"TERA_SHARD", type: teraType }]);
|
||||
game.override.enemyAbility(targetAbility);
|
||||
|
||||
const user = game.scene.addPlayerPokemon(getPokemonSpecies(Species.SNORLAX), 5);
|
||||
const target = game.scene.addEnemyPokemon(getPokemonSpecies(targetSpecies), 5, TrainerSlot.NONE);
|
||||
|
||||
if (teraType !== undefined) {
|
||||
overrideHeldItems(target, false);
|
||||
target.teraType = teraType;
|
||||
target.isTerastallized = true;
|
||||
}
|
||||
|
||||
expect(target.getMoveEffectiveness(user, allMoves[move])).toBe(expected);
|
||||
@ -40,7 +38,6 @@ describe("Moves - Type Effectiveness", () => {
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
game = new GameManager(phaserGame);
|
||||
TerastallizeModifier.prototype.apply = (args) => true;
|
||||
|
||||
game.override.ability(Abilities.BALL_FETCH);
|
||||
});
|
||||
|
@ -117,11 +117,12 @@ describe("Moves - Freeze-Dry", () => {
|
||||
});
|
||||
|
||||
it("should deal 2x damage to steel type terastallized into water", async () => {
|
||||
game.override.enemySpecies(Species.SKARMORY)
|
||||
.enemyHeldItems([{ name: "TERA_SHARD", type: Type.WATER }]);
|
||||
game.override.enemySpecies(Species.SKARMORY);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
enemy.teraType = Type.WATER;
|
||||
enemy.isTerastallized = true;
|
||||
vi.spyOn(enemy, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(Moves.FREEZE_DRY);
|
||||
@ -132,11 +133,12 @@ describe("Moves - Freeze-Dry", () => {
|
||||
});
|
||||
|
||||
it("should deal 0.5x damage to water type terastallized into fire", async () => {
|
||||
game.override.enemySpecies(Species.PELIPPER)
|
||||
.enemyHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }]);
|
||||
game.override.enemySpecies(Species.PELIPPER);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
enemy.teraType = Type.FIRE;
|
||||
enemy.isTerastallized = true;
|
||||
vi.spyOn(enemy, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(Moves.FREEZE_DRY);
|
||||
|
@ -83,10 +83,12 @@ describe("Moves - Tar Shot", () => {
|
||||
});
|
||||
|
||||
it("does not double the effectiveness of Fire-type moves against a Pokémon that is Terastallized", async () => {
|
||||
game.override.enemyHeldItems([{ name: "TERA_SHARD", type: Type.GRASS }]).enemySpecies(Species.SPRIGATITO);
|
||||
game.override.enemySpecies(Species.SPRIGATITO);
|
||||
await game.classicMode.startBattle([ Species.PIKACHU ]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
enemy.teraType = Type.GRASS;
|
||||
enemy.isTerastallized = true;
|
||||
|
||||
vi.spyOn(enemy, "getMoveEffectiveness");
|
||||
|
||||
@ -119,7 +121,8 @@ describe("Moves - Tar Shot", () => {
|
||||
|
||||
await game.toNextTurn();
|
||||
|
||||
game.override.enemyHeldItems([{ name: "TERA_SHARD", type: Type.GRASS }]);
|
||||
enemy.teraType = Type.GRASS;
|
||||
enemy.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.FIRE_PUNCH);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
|
@ -35,7 +35,6 @@ describe("Moves - Tera Blast", () => {
|
||||
.starterSpecies(Species.FEEBAS)
|
||||
.moveset([ Moves.TERA_BLAST ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.startingHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }])
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyMoveset(Moves.SPLASH)
|
||||
.enemyAbility(Abilities.STURDY)
|
||||
@ -45,13 +44,15 @@ describe("Moves - Tera Blast", () => {
|
||||
});
|
||||
|
||||
it("changes type to match user's tera type", async () => {
|
||||
game.override
|
||||
.enemySpecies(Species.FURRET)
|
||||
.startingHeldItems([{ name: "TERA_SHARD", type: Type.FIGHTING }]);
|
||||
game.override.enemySpecies(Species.FURRET);
|
||||
await game.startBattle();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
vi.spyOn(enemyPokemon, "apply");
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
playerPokemon.teraType = Type.FIGHTING;
|
||||
playerPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.TERA_BLAST);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
@ -60,10 +61,12 @@ describe("Moves - Tera Blast", () => {
|
||||
}, 20000);
|
||||
|
||||
it("increases power if user is Stellar tera type", async () => {
|
||||
game.override.startingHeldItems([{ name: "TERA_SHARD", type: Type.STELLAR }]);
|
||||
|
||||
await game.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
playerPokemon.teraType = Type.STELLAR;
|
||||
playerPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.TERA_BLAST);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
@ -72,13 +75,15 @@ describe("Moves - Tera Blast", () => {
|
||||
}, 20000);
|
||||
|
||||
it("is super effective against terastallized targets if user is Stellar tera type", async () => {
|
||||
game.override.startingHeldItems([{ name: "TERA_SHARD", type: Type.STELLAR }]);
|
||||
|
||||
await game.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
playerPokemon.teraType = Type.STELLAR;
|
||||
playerPokemon.isTerastallized = true;
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
vi.spyOn(enemyPokemon, "apply");
|
||||
vi.spyOn(enemyPokemon, "isTerastallized").mockReturnValue(true);
|
||||
enemyPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.TERA_BLAST);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
@ -93,6 +98,7 @@ describe("Moves - Tera Blast", () => {
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
playerPokemon.stats[Stat.ATK] = 100;
|
||||
playerPokemon.stats[Stat.SPATK] = 1;
|
||||
playerPokemon.isTerastallized = true;
|
||||
|
||||
vi.spyOn(teraBlastAttr, "apply");
|
||||
|
||||
@ -169,10 +175,11 @@ describe("Moves - Tera Blast", () => {
|
||||
|
||||
|
||||
it("causes stat drops if user is Stellar tera type", async () => {
|
||||
game.override.startingHeldItems([{ name: "TERA_SHARD", type: Type.STELLAR }]);
|
||||
await game.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
playerPokemon.teraType = Type.STELLAR;
|
||||
playerPokemon.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.TERA_BLAST);
|
||||
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||
|
@ -29,8 +29,7 @@ describe("Moves - Tera Starstorm", () => {
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.SPLASH)
|
||||
.enemyLevel(30)
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.startingHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }]);
|
||||
.enemySpecies(Species.MAGIKARP);
|
||||
});
|
||||
|
||||
it("changes type to Stellar when used by Terapagos in its Stellar Form", async () => {
|
||||
@ -38,19 +37,22 @@ describe("Moves - Tera Starstorm", () => {
|
||||
await game.classicMode.startBattle([ Species.TERAPAGOS ]);
|
||||
|
||||
const terapagos = game.scene.getPlayerPokemon()!;
|
||||
terapagos.isTerastallized = true;
|
||||
|
||||
vi.spyOn(terapagos, "getMoveType");
|
||||
|
||||
game.move.select(Moves.TERA_STARSTORM);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(terapagos.isTerastallized()).toBe(true);
|
||||
expect(terapagos.getMoveType).toHaveReturnedWith(Type.STELLAR);
|
||||
});
|
||||
|
||||
it("targets both opponents in a double battle when used by Terapagos in its Stellar Form", async () => {
|
||||
await game.classicMode.startBattle([ Species.MAGIKARP, Species.TERAPAGOS ]);
|
||||
|
||||
const terapagos = game.scene.getPlayerParty()[1];
|
||||
terapagos.isTerastallized = true;
|
||||
|
||||
game.move.select(Moves.TERA_STARSTORM, 0, BattlerIndex.ENEMY);
|
||||
game.move.select(Moves.TERA_STARSTORM, 1);
|
||||
|
||||
@ -82,6 +84,8 @@ describe("Moves - Tera Starstorm", () => {
|
||||
fusionedMon.fusionGender = magikarp.gender;
|
||||
fusionedMon.fusionLuck = magikarp.luck;
|
||||
|
||||
fusionedMon.isTerastallized = true;
|
||||
|
||||
vi.spyOn(fusionedMon, "getMoveType");
|
||||
|
||||
game.move.select(Moves.TERA_STARSTORM, 0);
|
||||
@ -90,7 +94,6 @@ describe("Moves - Tera Starstorm", () => {
|
||||
|
||||
// Fusion and terastallized
|
||||
expect(fusionedMon.isFusion()).toBe(true);
|
||||
expect(fusionedMon.isTerastallized()).toBe(true);
|
||||
// Move effects should be applied
|
||||
expect(fusionedMon.getMoveType).toHaveReturnedWith(Type.STELLAR);
|
||||
expect(game.scene.getEnemyField().every(pokemon => pokemon.isFullHp())).toBe(false);
|
||||
|
@ -324,9 +324,9 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
||||
this.lastTeraType = pokemon.getTeraType();
|
||||
|
||||
this.teraIcon.setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1, 2);
|
||||
this.teraIcon.setVisible(this.lastTeraType !== Type.UNKNOWN);
|
||||
this.teraIcon.setVisible(pokemon.isTerastallized);
|
||||
this.teraIcon.on("pointerover", () => {
|
||||
if (this.lastTeraType !== Type.UNKNOWN) {
|
||||
if (pokemon.isTerastallized) {
|
||||
globalScene.ui.showTooltip("", i18next.t("fightUiHandler:teraHover", { type: i18next.t(`pokemonInfo:Type.${Type[this.lastTeraType]}`) }));
|
||||
}
|
||||
});
|
||||
@ -542,7 +542,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
||||
this.genderText.setPositionRelative(this.nameText, this.nameText.displayWidth, 0);
|
||||
}
|
||||
|
||||
const teraType = pokemon.getTeraType();
|
||||
const teraType = pokemon.isTerastallized ? pokemon.getTeraType() : Type.UNKNOWN;
|
||||
const teraTypeUpdated = this.lastTeraType !== teraType;
|
||||
|
||||
if (teraTypeUpdated) {
|
||||
|
@ -7,18 +7,24 @@ import { Button } from "#enums/buttons";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { CommandPhase } from "#app/phases/command-phase";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { TerastallizeAccessModifier } from "#app/modifier/modifier";
|
||||
import { Type } from "#app/enums/type";
|
||||
import { getTypeRgb } from "#app/data/type";
|
||||
|
||||
export enum Command {
|
||||
FIGHT = 0,
|
||||
BALL,
|
||||
POKEMON,
|
||||
RUN
|
||||
RUN,
|
||||
TERA
|
||||
}
|
||||
|
||||
export default class CommandUiHandler extends UiHandler {
|
||||
private commandsContainer: Phaser.GameObjects.Container;
|
||||
private cursorObj: Phaser.GameObjects.Image | null;
|
||||
|
||||
private teraButton: Phaser.GameObjects.Sprite;
|
||||
|
||||
protected fieldIndex: number = 0;
|
||||
protected cursor2: number = 0;
|
||||
|
||||
@ -40,6 +46,13 @@ export default class CommandUiHandler extends UiHandler {
|
||||
this.commandsContainer.setVisible(false);
|
||||
ui.add(this.commandsContainer);
|
||||
|
||||
this.teraButton = globalScene.add.sprite(-32, 15, "button_tera");
|
||||
this.teraButton.setName("terrastallize-button");
|
||||
this.teraButton.setScale(1.3);
|
||||
this.teraButton.setFrame("fire");
|
||||
this.teraButton.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true, teraColor: getTypeRgb(Type.FIRE), isTerastallized: false });
|
||||
this.commandsContainer.add(this.teraButton);
|
||||
|
||||
for (let c = 0; c < commands.length; c++) {
|
||||
const commandText = addTextObject(c % 2 === 0 ? 0 : 55.8, c < 2 ? 0 : 16, commands[c], TextStyle.WINDOW);
|
||||
commandText.setName(commands[c]);
|
||||
@ -62,11 +75,22 @@ export default class CommandUiHandler extends UiHandler {
|
||||
commandPhase = globalScene.getStandbyPhase() as CommandPhase;
|
||||
}
|
||||
|
||||
if (this.canTera()) {
|
||||
this.teraButton.setVisible(true);
|
||||
this.teraButton.setFrame(Type[globalScene.getField()[this.fieldIndex].getTeraType()].toLowerCase());
|
||||
} else {
|
||||
this.teraButton.setVisible(false);
|
||||
if (this.cursor === Command.TERA) {
|
||||
this.setCursor(Command.FIGHT);
|
||||
}
|
||||
}
|
||||
this.toggleTeraButton();
|
||||
|
||||
const messageHandler = this.getUi().getMessageHandler();
|
||||
messageHandler.bg.setVisible(true);
|
||||
messageHandler.commandWindow.setVisible(true);
|
||||
messageHandler.movesWindowContainer.setVisible(false);
|
||||
messageHandler.message.setWordWrapWidth(1110);
|
||||
messageHandler.message.setWordWrapWidth(this.canTera() ? 910 : 1110);
|
||||
messageHandler.showText(i18next.t("commandUiHandler:actionMessage", { pokemonName: getPokemonNameWithAffix(commandPhase.getPokemon()) }), 0);
|
||||
if (this.getCursor() === Command.POKEMON) {
|
||||
this.setCursor(Command.FIGHT);
|
||||
@ -108,6 +132,10 @@ export default class CommandUiHandler extends UiHandler {
|
||||
(globalScene.getCurrentPhase() as CommandPhase).handleCommand(Command.RUN, 0);
|
||||
success = true;
|
||||
break;
|
||||
case Command.TERA:
|
||||
ui.setMode(Mode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex(), Command.TERA);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
(globalScene.getCurrentPhase() as CommandPhase).cancel();
|
||||
@ -115,23 +143,29 @@ export default class CommandUiHandler extends UiHandler {
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button.UP:
|
||||
if (cursor >= 2) {
|
||||
if (cursor === Command.POKEMON || cursor === Command.RUN) {
|
||||
success = this.setCursor(cursor - 2);
|
||||
}
|
||||
break;
|
||||
case Button.DOWN:
|
||||
if (cursor < 2) {
|
||||
if (cursor === Command.FIGHT || cursor === Command.BALL) {
|
||||
success = this.setCursor(cursor + 2);
|
||||
}
|
||||
break;
|
||||
case Button.LEFT:
|
||||
if (cursor % 2 === 1) {
|
||||
if (cursor === Command.BALL || cursor === Command.RUN) {
|
||||
success = this.setCursor(cursor - 1);
|
||||
} else if ((cursor === Command.FIGHT || cursor === Command.POKEMON) && this.canTera()) {
|
||||
success = this.setCursor(Command.TERA);
|
||||
this.toggleTeraButton();
|
||||
}
|
||||
break;
|
||||
case Button.RIGHT:
|
||||
if (cursor % 2 === 0) {
|
||||
if (cursor === Command.FIGHT || cursor === Command.POKEMON) {
|
||||
success = this.setCursor(cursor + 1);
|
||||
} else if (cursor === Command.TERA) {
|
||||
success = this.setCursor(Command.FIGHT);
|
||||
this.toggleTeraButton();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -144,6 +178,17 @@ export default class CommandUiHandler extends UiHandler {
|
||||
return success;
|
||||
}
|
||||
|
||||
canTera(): boolean {
|
||||
const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length;
|
||||
const currentTeras = globalScene.arena.playerTerasUsed;
|
||||
const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 ? 1 : 0;
|
||||
return hasTeraMod && (currentTeras + plannedTera) < 1;
|
||||
}
|
||||
|
||||
toggleTeraButton() {
|
||||
this.teraButton.setPipeline(globalScene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true, teraColor: getTypeRgb(globalScene.getField()[this.fieldIndex].getTeraType()), isTerastallized: this.getCursor() === Command.TERA });
|
||||
}
|
||||
|
||||
getCursor(): number {
|
||||
return !this.fieldIndex ? this.cursor : this.cursor2;
|
||||
}
|
||||
@ -163,7 +208,12 @@ export default class CommandUiHandler extends UiHandler {
|
||||
this.commandsContainer.add(this.cursorObj);
|
||||
}
|
||||
|
||||
this.cursorObj.setPosition(-5 + (cursor % 2 === 1 ? 56 : 0), 8 + (cursor >= 2 ? 16 : 0));
|
||||
if (cursor === Command.TERA) {
|
||||
this.cursorObj.setVisible(false);
|
||||
} else {
|
||||
this.cursorObj.setPosition(-5 + (cursor % 2 === 1 ? 56 : 0), 8 + (cursor >= 2 ? 16 : 0));
|
||||
this.cursorObj.setVisible(true);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
||||
private moveInfoOverlay : MoveInfoOverlay;
|
||||
|
||||
protected fieldIndex: number = 0;
|
||||
protected fromCommand: Command = Command.FIGHT;
|
||||
protected cursor2: number = 0;
|
||||
|
||||
constructor() {
|
||||
@ -114,6 +115,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
||||
super.show(args);
|
||||
|
||||
this.fieldIndex = args.length ? args[0] as number : 0;
|
||||
this.fromCommand = args.length > 1 ? args[1] as Command : Command.FIGHT;
|
||||
|
||||
const messageHandler = this.getUi().getMessageHandler();
|
||||
messageHandler.bg.setVisible(false);
|
||||
@ -140,7 +142,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
||||
|
||||
if (button === Button.CANCEL || button === Button.ACTION) {
|
||||
if (button === Button.ACTION) {
|
||||
if ((globalScene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, cursor, false)) {
|
||||
if ((globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, false)) {
|
||||
success = true;
|
||||
} else {
|
||||
ui.playError();
|
||||
|
@ -420,17 +420,6 @@ export default class RunInfoUiHandler extends UiHandler {
|
||||
private parseTrainerDefeat(enemyContainer: Phaser.GameObjects.Container) {
|
||||
// Loads and adds trainer sprites to the UI
|
||||
this.showTrainerSprites(enemyContainer);
|
||||
// Determining which Terastallize Modifier belongs to which Pokemon
|
||||
// Creates a dictionary {PokemonId: TeraShardType}
|
||||
const teraPokemon = {};
|
||||
this.runInfo.enemyModifiers.forEach((m) => {
|
||||
const modifier = m.toModifier(this.modifiersModule[m.className]);
|
||||
if (modifier instanceof Modifier.TerastallizeModifier) {
|
||||
const teraDetails = modifier?.getArgs();
|
||||
const pkmnId = teraDetails[0];
|
||||
teraPokemon[pkmnId] = teraDetails[1];
|
||||
}
|
||||
});
|
||||
|
||||
// Creates the Pokemon icons + level information and adds it to enemyContainer
|
||||
// 2 Rows x 3 Columns
|
||||
@ -444,18 +433,6 @@ export default class RunInfoUiHandler extends UiHandler {
|
||||
enemyData["player"] = true;
|
||||
const enemy = enemyData.toPokemon();
|
||||
const enemyIcon = globalScene.addPokemonIcon(enemy, 0, 0, 0, 0);
|
||||
// Applying Terastallizing Type tint to Pokemon icon
|
||||
// If the Pokemon is a fusion, it has two sprites and so, the tint has to be applied to each icon separately
|
||||
const enemySprite1 = enemyIcon.list[0] as Phaser.GameObjects.Sprite;
|
||||
const enemySprite2 = (enemyIcon.list.length > 1) ? enemyIcon.list[1] as Phaser.GameObjects.Sprite : undefined;
|
||||
if (teraPokemon[enemyData.id]) {
|
||||
const teraTint = getTypeRgb(teraPokemon[enemyData.id]);
|
||||
const teraColor = new Phaser.Display.Color(teraTint[0], teraTint[1], teraTint[2]);
|
||||
enemySprite1.setTint(teraColor.color);
|
||||
if (enemySprite2) {
|
||||
enemySprite2.setTint(teraColor.color);
|
||||
}
|
||||
}
|
||||
enemyIcon.setPosition(39 * (e % 3) + 5, (35 * pokemonRowHeight));
|
||||
const enemyLevel = addTextObject(43 * (e % 3), (27 * (pokemonRowHeight + 1)), `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, isBoss ? TextStyle.PARTY_RED : TextStyle.PARTY, { fontSize: "54px" });
|
||||
enemyLevel.setShadow(0, 0, undefined);
|
||||
|
@ -334,6 +334,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||
}
|
||||
this.pokemonSprite.setPipelineData("teraColor", getTypeRgb(this.pokemon.getTeraType()));
|
||||
this.pokemonSprite.setPipelineData("isTerastallized", this.pokemon.isTerastallized);
|
||||
this.pokemonSprite.setPipelineData("ignoreTimeTint", true);
|
||||
this.pokemonSprite.setPipelineData("spriteKey", this.pokemon.getSpriteKey());
|
||||
this.pokemonSprite.setPipelineData("shiny", this.pokemon.shiny);
|
||||
@ -782,7 +783,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
if (types.length > 1) {
|
||||
profileContainer.add(getTypeIcon(1, types[1]));
|
||||
}
|
||||
if (this.pokemon?.isTerastallized()) {
|
||||
if (this.pokemon?.isTerastallized) {
|
||||
profileContainer.add(getTypeIcon(types.length, this.pokemon.getTeraType(), true));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user