Skip to content

Commit

Permalink
Merge branch 'master' into human-synergy-rework
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvainpolletvillard authored Dec 18, 2024
2 parents ea73e83 + 59b978a commit de62a03
Show file tree
Hide file tree
Showing 19 changed files with 151 additions and 78 deletions.
8 changes: 2 additions & 6 deletions app/core/abilities/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4087,9 +4087,7 @@ export class ThiefStrategy extends AbilityStrategy {
}

target.items.forEach((item) => {
if (pokemon.items.size < 3) {
pokemon.addItem(item)
}
pokemon.addItem(item)
target.removeItem(item)
})

Expand Down Expand Up @@ -10409,9 +10407,7 @@ export class TrickOrTreatStrategy extends AbilityStrategy {
if (target.items.size > 0) {
const item = values(target.items)[0]!
target.removeItem(item)
if (pokemon.items.size < 3) {
pokemon.addItem(item)
}
pokemon.addItem(item)
} else if (pokemon.ap <= 50) {
// 0-50 AP: shrink unit size and HP
const lifeReduction = 0.4 / (1 + pokemon.ap / 100)
Expand Down
12 changes: 3 additions & 9 deletions app/core/abilities/hidden-power.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ export class HiddenPowerCStrategy extends HiddenPowerStrategy {
board.forEach(
(x: number, y: number, pokemon: PokemonEntity | undefined) => {
if (pokemon && unown.team === pokemon.team) {
if (pokemon.items.size < 3) {
pokemon.addItem(Item.AMULET_COIN)
}
pokemon.addItem(Item.AMULET_COIN)
}
}
)
Expand Down Expand Up @@ -358,9 +356,7 @@ export class HiddenPowerOStrategy extends HiddenPowerStrategy {
super.process(pokemon, state, board, target, crit)
board.forEach((x: number, y: number, value: PokemonEntity | undefined) => {
if (value && pokemon.team === value.team) {
if (value.items.size < 3) {
value.addItem(Item.ORAN_BERRY)
}
value.addItem(Item.ORAN_BERRY)
}
})
}
Expand Down Expand Up @@ -576,9 +572,7 @@ export class HiddenPowerXStrategy extends HiddenPowerStrategy {
board.forEach(
(x: number, y: number, pokemon: PokemonEntity | undefined) => {
if (pokemon && unown.team === pokemon.team) {
if (pokemon.items.size < 3) {
pokemon.addItem(Item.XRAY_VISION)
}
pokemon.addItem(Item.XRAY_VISION)
}
}
)
Expand Down
21 changes: 20 additions & 1 deletion app/core/pokemon-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
Stat,
Team
} from "../types/enum/Game"
import { Berries, Item } from "../types/enum/Item"
import { Berries, Item, SynergyGivenByItem } from "../types/enum/Item"
import { Passive } from "../types/enum/Passive"
import { Pkm, PkmIndex } from "../types/enum/Pokemon"
import { SpecialGameRule } from "../types/enum/SpecialGameRule"
Expand All @@ -57,6 +57,7 @@ import Simulation from "./simulation"
import { DelayedCommand, SimulationCommand } from "./simulation-command"
import { ItemEffects } from "./items"
import { OnItemRemovedEffect } from "./effect"
import { getPokemonData } from "../models/precomputed/precomputed-pokemon-data"

export class PokemonEntity extends Schema implements IPokemonEntity {
@type("boolean") shiny: boolean
Expand Down Expand Up @@ -593,11 +594,20 @@ export class PokemonEntity extends Schema implements IPokemonEntity {
}

addItem(item: Item, permanent = false) {
if (this.items.size >= 3) {
return
}
this.items.add(item)
this.simulation.applyItemEffect(this, item)
if (permanent && !this.isGhostOpponent) {
this.refToBoardPokemon.items.add(item)
}

const type = SynergyGivenByItem[item]
if(type && !this.types.has(type)){
this.types.add(type)
this.simulation.applySynergyEffects(this, type)
}
}

removeItem(item: Item, permanent = false) {
Expand All @@ -615,6 +625,15 @@ export class PokemonEntity extends Schema implements IPokemonEntity {
)
}

const type = SynergyGivenByItem[item]
const default_types = getPokemonData(this.name).types
if (type && !default_types.includes(type)) {
this.types.delete(type)
SynergyEffects[type].forEach((effect) => {
this.effects.delete(effect)
})
}

ItemEffects[item]
?.filter((effect) => effect instanceof OnItemRemovedEffect)
?.forEach((effect) => effect.apply(this))
Expand Down
2 changes: 1 addition & 1 deletion app/core/pokemon-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export default abstract class PokemonState {
if (pokemon.items.has(Item.SILK_SCARF)) shield *= 1.3

shield = Math.round(shield)
pokemon.shield += shield
pokemon.shield = min(0)(pokemon.shield + shield)
if (caster && shield > 0) {
if (pokemon.simulation.room.state.time < FIGHTING_PHASE_DURATION) {
pokemon.simulation.room.broadcast(Transfer.POKEMON_HEAL, {
Expand Down
51 changes: 31 additions & 20 deletions app/core/simulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
} from "../types/enum/Item"
import { Passive } from "../types/enum/Passive"
import { Pkm } from "../types/enum/Pokemon"
import { Synergy } from "../types/enum/Synergy"
import { Synergy, SynergyEffects } from "../types/enum/Synergy"
import { Weather } from "../types/enum/Weather"
import { IPokemonData } from "../types/interfaces/PokemonData"
import { count } from "../utils/array"
Expand Down Expand Up @@ -370,27 +370,38 @@ export default class Simulation extends Schema implements ISimulation {
?.forEach((effect) => effect.apply(pokemon))
}

applySynergyEffects(pokemon: PokemonEntity) {
if (pokemon.team === Team.BLUE_TEAM) {
this.blueEffects.forEach((effect) => {
this.applyEffect(
pokemon,
pokemon.types,
effect,
this.bluePlayer?.synergies.countActiveSynergies() || 0
)
})
} else if (pokemon.team === Team.RED_TEAM) {
this.redEffects.forEach((effect) => {
this.applyEffect(
pokemon,
pokemon.types,
effect,
this.redPlayer?.synergies.countActiveSynergies() || 0
)
applySynergyEffects(pokemon: PokemonEntity, singleType?: Synergy) {
const allyEffects = pokemon.team === Team.BLUE_TEAM ?
this.blueEffects :
this.redEffects
const player = pokemon.team === Team.BLUE_TEAM ?
this.bluePlayer :
this.redPlayer
const apply = (effect) => {
this.applyEffect(
pokemon,
pokemon.types,
effect,
player?.synergies.countActiveSynergies() || 0
)
}

if(singleType){
const effect = SynergyEffects[singleType]
.find((e) => allyEffects.has(e))
if (effect && !pokemon.effects.has(effect)){
apply(effect)
}
} else {
allyEffects.forEach((effect) => {
apply(effect)
})
}
if (pokemon.types.has(Synergy.GHOST)) {

if (
(singleType === Synergy.GHOST) ||
(!singleType && pokemon.types.has(Synergy.GHOST))
) {
pokemon.addDodgeChance(0.2, pokemon, 0, false)
}
}
Expand Down
14 changes: 7 additions & 7 deletions app/models/colyseus-models/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11336,7 +11336,7 @@ export class Heliolisk extends Pokemon {
passive = Passive.DRY_SKIN
additional = true
attackSprite = AttackSprite.ELECTRIC_RANGE
afterSimulationStart({
onSpawn({
entity,
simulation
}: { entity: IPokemonEntity; simulation: Simulation }) {
Expand Down Expand Up @@ -11555,7 +11555,7 @@ export class Barboach extends Pokemon {
passive = Passive.AQUA_VEIL
additional = true
attackSprite = AttackSprite.WATER_MELEE
afterSimulationStart({
onSpawn({
entity,
simulation
}: { entity: IPokemonEntity; simulation: Simulation }) {
Expand All @@ -11579,7 +11579,7 @@ export class Whiscash extends Pokemon {
passive = Passive.AQUA_VEIL
additional = true
attackSprite = AttackSprite.WATER_MELEE
afterSimulationStart({
onSpawn({
entity,
simulation
}: { entity: IPokemonEntity; simulation: Simulation }) {
Expand Down Expand Up @@ -12719,7 +12719,7 @@ export class Smeargle extends Pokemon {
skill = Ability.SKETCH
attackSprite = AttackSprite.NORMAL_MELEE

onSpawn({ entity }) {
afterSimulationStart({ entity }) {
if (entity.player) {
const allyOnTheLeft = entity.player.getPokemonAt(
this.positionX - 1,
Expand Down Expand Up @@ -13964,7 +13964,7 @@ export class Trubbish extends Pokemon {
})
}

afterSimulationStart({ entity }: { entity: IPokemonEntity }) {
onSpawn({ entity }: { entity: IPokemonEntity }) {
// Add non-permanent stats to Trubbish
entity.addAbilityPower(this.statIncreases[Stat.AP], entity, 0, false)
entity.addShield(this.statIncreases[Stat.SHIELD], entity, 0, false)
Expand Down Expand Up @@ -14039,7 +14039,7 @@ export class Garbodor extends Pokemon {
}

beforeSimulationStart = Trubbish.prototype.beforeSimulationStart
afterSimulationStart = Trubbish.prototype.afterSimulationStart
onSpawn = Trubbish.prototype.onSpawn
}

export class Grubbin extends Pokemon {
Expand Down Expand Up @@ -14803,7 +14803,7 @@ export class Skarmory extends Pokemon {
attackSprite = AttackSprite.STEEL_MELEE
passive = Passive.SKARMORY

onSpawn(params: {
afterSimulationStart(params: {
player: IPlayer
simulation: Simulation
entity: IPokemonEntity
Expand Down
10 changes: 8 additions & 2 deletions app/public/dist/client/changelog/patch-5.9.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,15 @@
- Removed Amulet coin base stats
- Tiny mushroom now reduces health by 50% only if the holder is cloned
- Pokemons can now hold artificial items and Shiny Stone even if they give one of their existing synergies

- Max Revive is now consumed on use (stats are lost after resurrection)
- Item effects are now updated when items are gained or lost in battle
- Stats and statuses are now lost when items are removed
- Synergy effects and types are now added and removed accordingly
- Stat increases from the synergy of an item are gained when added, but not lost when removed

# Gameplay

- New status: Blinded: reduce accuracy of basic attacks by 50%. Replace the existing Smoke effect that was not considered a status.
- New rank system: 12 different ranks, each with a different icon (by @joinity). Beast ball and Master ball players will create ranked games with Ultra ball.
- Level ball: 0 ELO
- Net ball: 1050 ELO
Expand All @@ -67,7 +73,7 @@
- Master ball: 1500 ELO
- Beast ball: 1700 ELO
- ELO, XP and titles after game are now distributed immediately after the player is eliminated and leaves the game, instead of waiting for the game to end
- New status: Blinded: reduce accuracy of basic attacks by 50%. Replace the existing Smoke effect that was not considered a status.
- Due to an increase of cases of intentional leaves at the start of a game, we have to increase the penalties for early disconnections. Intentional disconnections before stage 6 are no longer protected against Elo loss. Unintentional disconnections without reconnection within the next 3 minutes before stage 6 remain protected against Elo loss, but players won't be able to join a new game within the next 5 minutes.

# UI

Expand Down
3 changes: 2 additions & 1 deletion app/public/dist/client/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2177,7 +2177,7 @@
"GOOD_ROD": "After each PvP round, fish a Pokémon that is then added to a free slot on your bench. Can catch rare WATER Pokémons and Feebas.",
"SUPER_ROD": "After each PvP round, fish a Pokémon that is then added to a free slot on your bench. Can catch epic WATER Pokémons and Wishiwashi.",
"DYNAMAX_BAND": "At the start of the fight, raise max HP by 250%.",
"SHINY_STONE": "Gives +2 to LIGHT synergy and spawn a second light spot on the holder's cell",
"SHINY_STONE": "Gives LIGHT synergy and +1 to LIGHT synergy level. Spawn a second light spot on the holder's cell.",
"RARE_CANDY": "Immediately make a Pokémon evolve. Can only be given to non-fully evolved Pokémon, and reduce its sell price to its previous tier.",
"EVIOLITE": "Holder gets a bunch of stats, but can no longer evolve. Can only be given to non-fully evolved Pokémon.",
"WHITE_FLUTE": "Spawn 3 WILD Pokémons around the holder at the start of the fight. Rarity and tier increase with stage level.",
Expand Down Expand Up @@ -3409,6 +3409,7 @@
"USER_BANNED": "You account has been banned",
"USER_RANK_TOO_LOW": "Your player rank is not high enough to participate in this lobby",
"USER_NOT_AUTHENTICATED": "Please authenticate again",
"USER_TIMEOUT": "You recently left a game before its end, so you have to wait 5 minutes before joining another one",
"ROOM_FULL": "This room is full",
"ROOM_EMPTY": "This room has been removed due to lack of players",
"ROOM_DELETED": "This room has been deleted",
Expand Down
7 changes: 6 additions & 1 deletion app/public/src/game/lobby-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ export async function joinExistingPreparationRoom(
navigate("/preparation")
}
} catch (error) {
logger.error(error)
if (error.code && error.code in CloseCodesMessages) {
const errorMessage = CloseCodesMessages[error.code]
dispatch(setErrorAlertMessage(t(`errors.${errorMessage}`)))
} else {
logger.error(error)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ export default function AvailableRoomMenu() {
)
const uid: string = useAppSelector((state) => state.network.uid)
const user = useAppSelector((state) => state.network.profile)
const [isJoining, setJoining] = useState<boolean>(false)
const [showRoomSelectionMenu, setShowRoomSelectionMenu] = useState<boolean>(false)

const requestRoom = throttle(async function (gameMode: GameMode) {
if (lobby && !isJoining) {
setJoining(true)
if (lobby) {
lobby.send(Transfer.REQUEST_ROOM, gameMode)
setShowRoomSelectionMenu(false)
}
}, 1000)

Expand All @@ -58,13 +57,11 @@ export default function AvailableRoomMenu() {
return
}

if (lobby && !isJoining) {
if (password) {
if (user && user.role === Role.BASIC) {
const password = prompt(`This room is private. Enter password`)
if (selectedRoom.metadata?.password != password)
return alert(`Wrong password !`)
}
if (lobby) {
if (password && user && user.role === Role.BASIC) {
const password = prompt(`This room is private. Enter password`)
if (selectedRoom.metadata?.password != password)
return alert(`Wrong password !`)
}

await joinExistingPreparationRoom(selectedRoom.roomId, client, lobby, dispatch, navigate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
padding: 1em 0.5em;
}

.room-selection-menu li > * {
user-select: none;
}

.room-selection-menu li:hover {
background-color: var(--color-bg-accent);
cursor: var(--cursor-hover);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ export function RoomSelectionMenu(props: { show: boolean, onClose: () => void, o
header={t("new_game")}
body={<ul>
<li className="my-box" onClick={() => props.onSelectMode(GameMode.QUICKPLAY)}>
<img src="assets/ui/game_modes/quickplay.png" alt="Quick Play" />
<img src="assets/ui/game_modes/quickplay.png" alt="Quick Play" draggable="false" />
<h2>{t("quick_play")}</h2>
<p>{t("quick_play_description")}</p>
</li>
<li className="my-box" onClick={() => props.onSelectMode(GameMode.RANKED)}>
<img src="assets/ui/game_modes/ranked.png" alt="Ranked match" />
<img src="assets/ui/game_modes/ranked.png" alt="Ranked match" draggable="false" />
<h2>{t("ranked_match")}</h2>
<p>{t("ranked_match_description")}</p>
</li>
<li className="my-box" onClick={() => props.onSelectMode(GameMode.SCRIBBLE)}>
<img src="assets/ui/game_modes/scribble.png" alt="Smeargle's Scribble" />
<img src="assets/ui/game_modes/scribble.png" alt="Smeargle's Scribble" draggable="false" />
<h2>{t("smeargle_scribble")}</h2>
<p>{t("smeargle_scribble_description")}</p>
</li>
<li className="my-box" onClick={() => props.onSelectMode(GameMode.CUSTOM_LOBBY)}>
<img src="assets/ui/game_modes/custom.png" alt="Custom lobby" />
<img src="assets/ui/game_modes/custom.png" alt="Custom lobby" draggable="false" />
<h2>{t("custom_room")}</h2>
<p>{t("custom_room_description")}</p>
</li>
Expand Down
11 changes: 10 additions & 1 deletion app/public/src/pages/preparation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,16 @@ export default function Preparation() {
})

r.onLeave((code) => {
const shouldGoToLobby = (code === CloseCodes.USER_KICKED || code === CloseCodes.ROOM_DELETED || code === CloseCodes.ROOM_FULL || code === CloseCodes.ROOM_EMPTY || code === CloseCodes.USER_BANNED || code === CloseCodes.USER_RANK_TOO_LOW)
const shouldGoToLobby = [
CloseCodes.USER_KICKED,
CloseCodes.ROOM_DELETED,
CloseCodes.ROOM_FULL,
CloseCodes.ROOM_EMPTY,
CloseCodes.USER_BANNED,
CloseCodes.USER_RANK_TOO_LOW,
CloseCodes.USER_TIMEOUT
].includes(code)

const shouldReconnect = code === CloseCodes.ABNORMAL_CLOSURE || code === CloseCodes.TIMEOUT
logger.info(`left preparation room with code ${code}`, { shouldGoToLobby, shouldReconnect })

Expand Down
Loading

0 comments on commit de62a03

Please sign in to comment.