diff --git a/src/main/java/emu/grasscutter/Language.java b/src/main/java/emu/grasscutter/Language.java index 6d30eb404..bb765dc19 100644 --- a/src/main/java/emu/grasscutter/Language.java +++ b/src/main/java/emu/grasscutter/Language.java @@ -204,41 +204,51 @@ public final class Language { public String SetFetterLevel_invalid_fetter_level = "Invalid fetter level."; // SetStats - public String SetStats_usage = "Usage: setstats|stats "; - public String SetStats_setstats_help_message = "Usage: /setstats|stats for basic stats"; - public String SetStats_stats_help_message = "Usage: /stats for elemental bonus"; + public String SetStats_usage_console = "Usage: setstats|stats @ "; + public String SetStats_usage_ingame = "Usage: setstats|stats [@UID] "; + public String SetStats_help_message = """ + \n\tValues for : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi + \t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys + \t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys + """; + public String SetStats_value_error = "Invalid stat value."; + public String SetStats_uid_error = "Invalid UID."; + public String SetStats_player_error = "Player not found or offline."; + public String SetStats_set_self = "%s set to %s."; + public String SetStats_set_for_uid = "%s for %s set to %s."; public String SetStats_set_max_hp = "MAX HP set to %s."; - public String SetStats_set_max_hp_error = "Invalid Max HP value."; - public String SetStats_set_hp = "HP set to %s."; - public String SetStats_set_hp_error = "Invalid HP value."; - public String SetStats_set_def = "DEF set to %s."; - public String SetStats_set_def_error = "Invalid DEF value."; - public String SetStats_set_atk = "ATK set to %s."; - public String SetStats_set_atk_error = "Invalid ATK value."; - public String SetStats_set_em = "Elemental Mastery set to %s."; - public String SetStats_set_em_error = "Invalid EM value."; - public String SetStats_set_er = "Energy recharge set to %s%."; - public String SetStats_set_er_error = "Invalid ER value."; - public String SetStats_set_cr = "Crit Rate set to %s%."; - public String SetStats_set_cr_error = "Invalid Crit Rate value."; - public String SetStats_set_cd = "Crit DMG set to %s%."; - public String SetStats_set_cd_error = "Invalid Crit DMG value."; - public String SetStats_set_pdb = "Pyro DMG Bonus set to %s%."; - public String SetStats_set_pdb_error = "Invalid Pyro DMG Bonus value."; - public String SetStats_set_cdb = "Cyro DMG Bonus set to %s%."; - public String SetStats_set_cdb_error = "Invalid Cyro DMG Bonus value."; - public String SetStats_set_hdb = "Hydro DMG Bonus set to %s%."; - public String SetStats_set_hdb_error = "Invalid Hydro DMG Bonus value."; - public String SetStats_set_adb = "Anemo DMG Bonus set to %s%."; - public String SetStats_set_adb_error = "Invalid Anemo DMG Bonus value."; - public String SetStats_set_gdb = "Geo DMG Bonus set to %s%."; - public String SetStats_set_gdb_error = "Invalid Geo DMG Bonus value."; - public String SetStats_set_edb = "Electro DMG Bonus set to %s%."; - public String SetStats_set_edb_error = "Invalid Electro DMG Bonus value."; - public String SetStats_set_physdb = "Physical DMG Bonus set to %s%."; - public String SetStats_set_physdb_error = "Invalid Physical DMG Bonus value."; - public String SetStats_set_ddb = "Dendro DMG Bonus set to %s%."; - public String SetStats_set_ddb_error = "Invalid Dendro DMG Bonus value."; + public String Stats_FIGHT_PROP_MAX_HP = "Max HP"; + public String Stats_FIGHT_PROP_CUR_HP = "Current HP"; + public String Stats_FIGHT_PROP_CUR_ATTACK = "ATK"; + public String Stats_FIGHT_PROP_BASE_ATTACK = "Base ATK"; + public String Stats_FIGHT_PROP_DEFENSE = "DEF"; + public String Stats_FIGHT_PROP_ELEMENT_MASTERY = "Elemental Mastery"; + public String Stats_FIGHT_PROP_CHARGE_EFFICIENCY = "Energy Recharge"; + public String Stats_FIGHT_PROP_CRITICAL = "Crit Rate"; + public String Stats_FIGHT_PROP_CRITICAL_HURT = "Crit DMG"; + public String Stats_FIGHT_PROP_ADD_HURT = "DMG Bonus"; + public String Stats_FIGHT_PROP_WIND_ADD_HURT = "Anemo DMG Bonus"; + public String Stats_FIGHT_PROP_ICE_ADD_HURT = "Cryo DMG Bonus"; + public String Stats_FIGHT_PROP_GRASS_ADD_HURT = "Dendro DMG Bonus"; + public String Stats_FIGHT_PROP_ELEC_ADD_HURT = "Electro DMG Bonus"; + public String Stats_FIGHT_PROP_ROCK_ADD_HURT = "Geo DMG Bonus"; + public String Stats_FIGHT_PROP_WATER_ADD_HURT = "Hydro DMG Bonus"; + public String Stats_FIGHT_PROP_FIRE_ADD_HURT = "Pyro DMG Bonus"; + public String Stats_FIGHT_PROP_PHYSICAL_ADD_HURT = "Physical DMG Bonus"; + public String Stats_FIGHT_PROP_SUB_HURT = "DMG Reduction"; + public String Stats_FIGHT_PROP_WIND_SUB_HURT = "Anemo RES"; + public String Stats_FIGHT_PROP_ICE_SUB_HURT = "Cryo RES"; + public String Stats_FIGHT_PROP_GRASS_SUB_HURT = "Dendro RES"; + public String Stats_FIGHT_PROP_ELEC_SUB_HURT = "Electro RES"; + public String Stats_FIGHT_PROP_ROCK_SUB_HURT = "Geo RES"; + public String Stats_FIGHT_PROP_WATER_SUB_HURT = "Hydro RES"; + public String Stats_FIGHT_PROP_FIRE_SUB_HURT = "Pyro RES"; + public String Stats_FIGHT_PROP_PHYSICAL_SUB_HURT = "Physical RES"; + public String Stats_FIGHT_PROP_SKILL_CD_MINUS_RATIO = "Cooldown Reduction"; + public String Stats_FIGHT_PROP_HEAL_ADD = "Healing Bonus"; + public String Stats_FIGHT_PROP_HEALED_ADD = "Incoming Healing Bonus"; + public String Stats_FIGHT_PROP_SHIELD_COST_MINUS_RATIO = "Shield Strength"; + public String Stats_FIGHT_PROP_DEFENCE_IGNORE_RATIO = "DEF Ignore"; // SetWorldLevel public String SetWorldLevel_usage = "Usage: setworldlevel "; diff --git a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java index 6aceeff83..376e12589 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java @@ -1,6 +1,11 @@ package emu.grasscutter.command.commands; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import emu.grasscutter.Grasscutter; +import emu.grasscutter.Language; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.entity.EntityAvatar; @@ -8,245 +13,247 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; -import java.util.List; - -@Command(label = "setstats", usage = "setstats|stats ", +@Command(label = "setstats", usage = "setstats|stats [@UID] ", description = "Set fight property for your current active character", aliases = {"stats"}, permission = "player.setstats") public final class SetStatsCommand implements CommandHandler { + class Stat { + String name; + FightProperty prop; + boolean percent; + + public Stat(String name, FightProperty prop, boolean percent) { + this.name = name; + this.prop = prop; + this.percent = percent; + } + } + Map stats; + + public SetStatsCommand() { + Language lang = Grasscutter.getLanguage(); + stats = new HashMap(); + // Default stats + stats.put("maxhp", new Stat(lang.Stats_FIGHT_PROP_MAX_HP, FightProperty.FIGHT_PROP_MAX_HP, false)); + stats.put("hp", new Stat(lang.Stats_FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP, false)); + stats.put("atk", new Stat(lang.Stats_FIGHT_PROP_CUR_ATTACK, FightProperty.FIGHT_PROP_CUR_ATTACK, false)); + stats.put("atkb", new Stat(lang.Stats_FIGHT_PROP_BASE_ATTACK, FightProperty.FIGHT_PROP_BASE_ATTACK, false)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff. + stats.put("def", new Stat(lang.Stats_FIGHT_PROP_DEFENSE, FightProperty.FIGHT_PROP_DEFENSE, false)); + stats.put("em", new Stat(lang.Stats_FIGHT_PROP_ELEMENT_MASTERY, FightProperty.FIGHT_PROP_ELEMENT_MASTERY, false)); + stats.put("er", new Stat(lang.Stats_FIGHT_PROP_CHARGE_EFFICIENCY, FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true)); + stats.put("crate", new Stat(lang.Stats_FIGHT_PROP_CRITICAL, FightProperty.FIGHT_PROP_CRITICAL, true)); + stats.put("cdmg", new Stat(lang.Stats_FIGHT_PROP_CRITICAL_HURT, FightProperty.FIGHT_PROP_CRITICAL_HURT, true)); + stats.put("dmg", new Stat(lang.Stats_FIGHT_PROP_ADD_HURT, FightProperty.FIGHT_PROP_ADD_HURT, true)); // This seems to get reset after attacks + stats.put("eanemo", new Stat(lang.Stats_FIGHT_PROP_WIND_ADD_HURT, FightProperty.FIGHT_PROP_WIND_ADD_HURT, true)); + stats.put("ecryo", new Stat(lang.Stats_FIGHT_PROP_ICE_ADD_HURT, FightProperty.FIGHT_PROP_ICE_ADD_HURT, true)); + stats.put("edendro", new Stat(lang.Stats_FIGHT_PROP_GRASS_ADD_HURT, FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true)); + stats.put("eelectro", new Stat(lang.Stats_FIGHT_PROP_ELEC_ADD_HURT, FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true)); + stats.put("egeo", new Stat(lang.Stats_FIGHT_PROP_ROCK_ADD_HURT, FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true)); + stats.put("ehydro", new Stat(lang.Stats_FIGHT_PROP_WATER_ADD_HURT, FightProperty.FIGHT_PROP_WATER_ADD_HURT, true)); + stats.put("epyro", new Stat(lang.Stats_FIGHT_PROP_FIRE_ADD_HURT, FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true)); + stats.put("ephys", new Stat(lang.Stats_FIGHT_PROP_PHYSICAL_ADD_HURT, FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true)); + stats.put("resall", new Stat(lang.Stats_FIGHT_PROP_SUB_HURT, FightProperty.FIGHT_PROP_SUB_HURT, true)); // This seems to get reset after attacks + stats.put("resanemo", new Stat(lang.Stats_FIGHT_PROP_WIND_SUB_HURT, FightProperty.FIGHT_PROP_WIND_SUB_HURT, true)); + stats.put("rescryo", new Stat(lang.Stats_FIGHT_PROP_ICE_SUB_HURT, FightProperty.FIGHT_PROP_ICE_SUB_HURT, true)); + stats.put("resdendro", new Stat(lang.Stats_FIGHT_PROP_GRASS_SUB_HURT, FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true)); + stats.put("reselectro", new Stat(lang.Stats_FIGHT_PROP_ELEC_SUB_HURT, FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true)); + stats.put("resgeo", new Stat(lang.Stats_FIGHT_PROP_ROCK_SUB_HURT, FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true)); + stats.put("reshydro", new Stat(lang.Stats_FIGHT_PROP_WATER_SUB_HURT, FightProperty.FIGHT_PROP_WATER_SUB_HURT, true)); + stats.put("respyro", new Stat(lang.Stats_FIGHT_PROP_FIRE_SUB_HURT, FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true)); + stats.put("resphys", new Stat(lang.Stats_FIGHT_PROP_PHYSICAL_SUB_HURT, FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true)); + stats.put("cdr", new Stat(lang.Stats_FIGHT_PROP_SKILL_CD_MINUS_RATIO, FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true)); + stats.put("heal", new Stat(lang.Stats_FIGHT_PROP_HEAL_ADD, FightProperty.FIGHT_PROP_HEAL_ADD, true)); + stats.put("heali", new Stat(lang.Stats_FIGHT_PROP_HEALED_ADD, FightProperty.FIGHT_PROP_HEALED_ADD, true)); + stats.put("shield", new Stat(lang.Stats_FIGHT_PROP_SHIELD_COST_MINUS_RATIO, FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true)); + stats.put("defi", new Stat(lang.Stats_FIGHT_PROP_DEFENCE_IGNORE_RATIO, FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true)); + // Compatibility aliases + stats.put("mhp", stats.get("maxhp")); + stats.put("cr", stats.get("crate")); + stats.put("cd", stats.get("cdmg")); + stats.put("edend", stats.get("edendro")); + stats.put("eelec", stats.get("eelectro")); + stats.put("ethunder", stats.get("eelectro")); + + // Full FightProperty enum that won't be advertised but can be used by devs + // They have a prefix to avoid the "hp" clash + stats.put("_none", new Stat("NONE", FightProperty.FIGHT_PROP_NONE, true)); + stats.put("_base_hp", new Stat("BASE_HP", FightProperty.FIGHT_PROP_BASE_HP, false)); + stats.put("_hp", new Stat("HP", FightProperty.FIGHT_PROP_HP, false)); + stats.put("_hp_percent", new Stat("HP_PERCENT", FightProperty.FIGHT_PROP_HP_PERCENT, true)); + stats.put("_base_attack", new Stat("BASE_ATTACK", FightProperty.FIGHT_PROP_BASE_ATTACK, false)); + stats.put("_attack", new Stat("ATTACK", FightProperty.FIGHT_PROP_ATTACK, false)); + stats.put("_attack_percent", new Stat("ATTACK_PERCENT", FightProperty.FIGHT_PROP_ATTACK_PERCENT, true)); + stats.put("_base_defense", new Stat("BASE_DEFENSE", FightProperty.FIGHT_PROP_BASE_DEFENSE, false)); + stats.put("_defense", new Stat("DEFENSE", FightProperty.FIGHT_PROP_DEFENSE, false)); + stats.put("_defense_percent", new Stat("DEFENSE_PERCENT", FightProperty.FIGHT_PROP_DEFENSE_PERCENT, true)); + stats.put("_base_speed", new Stat("BASE_SPEED", FightProperty.FIGHT_PROP_BASE_SPEED, true)); + stats.put("_speed_percent", new Stat("SPEED_PERCENT", FightProperty.FIGHT_PROP_SPEED_PERCENT, true)); + stats.put("_hp_mp_percent", new Stat("HP_MP_PERCENT", FightProperty.FIGHT_PROP_HP_MP_PERCENT, true)); + stats.put("_attack_mp_percent", new Stat("ATTACK_MP_PERCENT", FightProperty.FIGHT_PROP_ATTACK_MP_PERCENT, true)); + stats.put("_critical", new Stat("CRITICAL", FightProperty.FIGHT_PROP_CRITICAL, true)); + stats.put("_anti_critical", new Stat("ANTI_CRITICAL", FightProperty.FIGHT_PROP_ANTI_CRITICAL, true)); + stats.put("_critical_hurt", new Stat("CRITICAL_HURT", FightProperty.FIGHT_PROP_CRITICAL_HURT, true)); + stats.put("_charge_efficiency", new Stat("CHARGE_EFFICIENCY", FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true)); + stats.put("_add_hurt", new Stat("ADD_HURT", FightProperty.FIGHT_PROP_ADD_HURT, true)); + stats.put("_sub_hurt", new Stat("SUB_HURT", FightProperty.FIGHT_PROP_SUB_HURT, true)); + stats.put("_heal_add", new Stat("HEAL_ADD", FightProperty.FIGHT_PROP_HEAL_ADD, true)); + stats.put("_healed_add", new Stat("HEALED_ADD", FightProperty.FIGHT_PROP_HEALED_ADD, false)); + stats.put("_element_mastery", new Stat("ELEMENT_MASTERY", FightProperty.FIGHT_PROP_ELEMENT_MASTERY, true)); + stats.put("_physical_sub_hurt", new Stat("PHYSICAL_SUB_HURT", FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true)); + stats.put("_physical_add_hurt", new Stat("PHYSICAL_ADD_HURT", FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true)); + stats.put("_defence_ignore_ratio", new Stat("DEFENCE_IGNORE_RATIO", FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true)); + stats.put("_defence_ignore_delta", new Stat("DEFENCE_IGNORE_DELTA", FightProperty.FIGHT_PROP_DEFENCE_IGNORE_DELTA, true)); + stats.put("_fire_add_hurt", new Stat("FIRE_ADD_HURT", FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true)); + stats.put("_elec_add_hurt", new Stat("ELEC_ADD_HURT", FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true)); + stats.put("_water_add_hurt", new Stat("WATER_ADD_HURT", FightProperty.FIGHT_PROP_WATER_ADD_HURT, true)); + stats.put("_grass_add_hurt", new Stat("GRASS_ADD_HURT", FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true)); + stats.put("_wind_add_hurt", new Stat("WIND_ADD_HURT", FightProperty.FIGHT_PROP_WIND_ADD_HURT, true)); + stats.put("_rock_add_hurt", new Stat("ROCK_ADD_HURT", FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true)); + stats.put("_ice_add_hurt", new Stat("ICE_ADD_HURT", FightProperty.FIGHT_PROP_ICE_ADD_HURT, true)); + stats.put("_hit_head_add_hurt", new Stat("HIT_HEAD_ADD_HURT", FightProperty.FIGHT_PROP_HIT_HEAD_ADD_HURT, true)); + stats.put("_fire_sub_hurt", new Stat("FIRE_SUB_HURT", FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true)); + stats.put("_elec_sub_hurt", new Stat("ELEC_SUB_HURT", FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true)); + stats.put("_water_sub_hurt", new Stat("WATER_SUB_HURT", FightProperty.FIGHT_PROP_WATER_SUB_HURT, true)); + stats.put("_grass_sub_hurt", new Stat("GRASS_SUB_HURT", FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true)); + stats.put("_wind_sub_hurt", new Stat("WIND_SUB_HURT", FightProperty.FIGHT_PROP_WIND_SUB_HURT, true)); + stats.put("_rock_sub_hurt", new Stat("ROCK_SUB_HURT", FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true)); + stats.put("_ice_sub_hurt", new Stat("ICE_SUB_HURT", FightProperty.FIGHT_PROP_ICE_SUB_HURT, true)); + stats.put("_effect_hit", new Stat("EFFECT_HIT", FightProperty.FIGHT_PROP_EFFECT_HIT, true)); + stats.put("_effect_resist", new Stat("EFFECT_RESIST", FightProperty.FIGHT_PROP_EFFECT_RESIST, true)); + stats.put("_freeze_resist", new Stat("FREEZE_RESIST", FightProperty.FIGHT_PROP_FREEZE_RESIST, true)); + stats.put("_torpor_resist", new Stat("TORPOR_RESIST", FightProperty.FIGHT_PROP_TORPOR_RESIST, true)); + stats.put("_dizzy_resist", new Stat("DIZZY_RESIST", FightProperty.FIGHT_PROP_DIZZY_RESIST, true)); + stats.put("_freeze_shorten", new Stat("FREEZE_SHORTEN", FightProperty.FIGHT_PROP_FREEZE_SHORTEN, true)); + stats.put("_torpor_shorten", new Stat("TORPOR_SHORTEN", FightProperty.FIGHT_PROP_TORPOR_SHORTEN, true)); + stats.put("_dizzy_shorten", new Stat("DIZZY_SHORTEN", FightProperty.FIGHT_PROP_DIZZY_SHORTEN, true)); + stats.put("_max_fire_energy", new Stat("MAX_FIRE_ENERGY", FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, true)); + stats.put("_max_elec_energy", new Stat("MAX_ELEC_ENERGY", FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, true)); + stats.put("_max_water_energy", new Stat("MAX_WATER_ENERGY", FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, true)); + stats.put("_max_grass_energy", new Stat("MAX_GRASS_ENERGY", FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY, true)); + stats.put("_max_wind_energy", new Stat("MAX_WIND_ENERGY", FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, true)); + stats.put("_max_ice_energy", new Stat("MAX_ICE_ENERGY", FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, true)); + stats.put("_max_rock_energy", new Stat("MAX_ROCK_ENERGY", FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, true)); + stats.put("_skill_cd_minus_ratio", new Stat("SKILL_CD_MINUS_RATIO", FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true)); + stats.put("_shield_cost_minus_ratio", new Stat("SHIELD_COST_MINUS_RATIO", FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true)); + stats.put("_cur_fire_energy", new Stat("CUR_FIRE_ENERGY", FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, false)); + stats.put("_cur_elec_energy", new Stat("CUR_ELEC_ENERGY", FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, false)); + stats.put("_cur_water_energy", new Stat("CUR_WATER_ENERGY", FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, false)); + stats.put("_cur_grass_energy", new Stat("CUR_GRASS_ENERGY", FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, false)); + stats.put("_cur_wind_energy", new Stat("CUR_WIND_ENERGY", FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, false)); + stats.put("_cur_ice_energy", new Stat("CUR_ICE_ENERGY", FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, false)); + stats.put("_cur_rock_energy", new Stat("CUR_ROCK_ENERGY", FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, false)); + stats.put("_cur_hp", new Stat("CUR_HP", FightProperty.FIGHT_PROP_CUR_HP, false)); + stats.put("_max_hp", new Stat("MAX_HP", FightProperty.FIGHT_PROP_MAX_HP, false)); + stats.put("_cur_attack", new Stat("CUR_ATTACK", FightProperty.FIGHT_PROP_CUR_ATTACK, false)); + stats.put("_cur_defense", new Stat("CUR_DEFENSE", FightProperty.FIGHT_PROP_CUR_DEFENSE, false)); + stats.put("_cur_speed", new Stat("CUR_SPEED", FightProperty.FIGHT_PROP_CUR_SPEED, true)); + stats.put("_nonextra_attack", new Stat("NONEXTRA_ATTACK", FightProperty.FIGHT_PROP_NONEXTRA_ATTACK, true)); + stats.put("_nonextra_defense", new Stat("NONEXTRA_DEFENSE", FightProperty.FIGHT_PROP_NONEXTRA_DEFENSE, true)); + stats.put("_nonextra_critical", new Stat("NONEXTRA_CRITICAL", FightProperty.FIGHT_PROP_NONEXTRA_CRITICAL, true)); + stats.put("_nonextra_anti_critical", new Stat("NONEXTRA_ANTI_CRITICAL", FightProperty.FIGHT_PROP_NONEXTRA_ANTI_CRITICAL, true)); + stats.put("_nonextra_critical_hurt", new Stat("NONEXTRA_CRITICAL_HURT", FightProperty.FIGHT_PROP_NONEXTRA_CRITICAL_HURT, true)); + stats.put("_nonextra_charge_efficiency", new Stat("NONEXTRA_CHARGE_EFFICIENCY", FightProperty.FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY, true)); + stats.put("_nonextra_element_mastery", new Stat("NONEXTRA_ELEMENT_MASTERY", FightProperty.FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY, true)); + stats.put("_nonextra_physical_sub_hurt", new Stat("NONEXTRA_PHYSICAL_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT, true)); + stats.put("_nonextra_fire_add_hurt", new Stat("NONEXTRA_FIRE_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT, true)); + stats.put("_nonextra_elec_add_hurt", new Stat("NONEXTRA_ELEC_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT, true)); + stats.put("_nonextra_water_add_hurt", new Stat("NONEXTRA_WATER_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WATER_ADD_HURT, true)); + stats.put("_nonextra_grass_add_hurt", new Stat("NONEXTRA_GRASS_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT, true)); + stats.put("_nonextra_wind_add_hurt", new Stat("NONEXTRA_WIND_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WIND_ADD_HURT, true)); + stats.put("_nonextra_rock_add_hurt", new Stat("NONEXTRA_ROCK_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT, true)); + stats.put("_nonextra_ice_add_hurt", new Stat("NONEXTRA_ICE_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ICE_ADD_HURT, true)); + stats.put("_nonextra_fire_sub_hurt", new Stat("NONEXTRA_FIRE_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT, true)); + stats.put("_nonextra_elec_sub_hurt", new Stat("NONEXTRA_ELEC_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT, true)); + stats.put("_nonextra_water_sub_hurt", new Stat("NONEXTRA_WATER_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WATER_SUB_HURT, true)); + stats.put("_nonextra_grass_sub_hurt", new Stat("NONEXTRA_GRASS_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT, true)); + stats.put("_nonextra_wind_sub_hurt", new Stat("NONEXTRA_WIND_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WIND_SUB_HURT, true)); + stats.put("_nonextra_rock_sub_hurt", new Stat("NONEXTRA_ROCK_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT, true)); + stats.put("_nonextra_ice_sub_hurt", new Stat("NONEXTRA_ICE_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ICE_SUB_HURT, true)); + stats.put("_nonextra_skill_cd_minus_ratio", new Stat("NONEXTRA_SKILL_CD_MINUS_RATIO", FightProperty.FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO, true)); + stats.put("_nonextra_shield_cost_minus_ratio", new Stat("NONEXTRA_SHIELD_COST_MINUS_RATIO", FightProperty.FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO, true)); + stats.put("_nonextra_physical_add_hurt", new Stat("NONEXTRA_PHYSICAL_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT, true)); + } @Override public void execute(Player sender, List args) { - if (sender == null) { - CommandHandler.sendMessage(null, Grasscutter.getLanguage().Run_this_command_in_game); - return; - } + Language lang = Grasscutter.getLanguage(); + String syntax = sender == null ? lang.SetStats_usage_console : lang.SetStats_usage_console; + String usage = syntax + lang.SetStats_help_message; + Player targetPlayer = sender; + String uidStr = ""; + String statStr; + String valueStr; - if (args.size() < 2){ - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_usage); - return; - } - - String stat = args.get(0); - switch (stat) { + switch (args.size()) { default: - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_setstats_help_message); - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_stats_help_message); + CommandHandler.sendMessage(sender, usage); return; - case "mhp": - try { - int health = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - entity.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, health); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_MAX_HP)); - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_max_hp, health)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_max_hp_error); + case 2: + if (sender == null) { + // When run by the server, first parameter is not optional + CommandHandler.sendMessage(sender, usage); return; } + statStr = args.get(0).toLowerCase(); + valueStr = args.get(1); break; - case "hp": - try { - int health = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_hp, health)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_hp_error); + case 3: + uidStr = args.get(0); + if (uidStr.startsWith("@")) { + uidStr = uidStr.substring(1); + } else { + CommandHandler.sendMessage(sender, usage); return; } - break; - case "def": try { - int def = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE, def); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_DEFENSE)); - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_def, def)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_def_error); - return; - } - break; - case "atk": - try { - int atk = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK, atk); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_ATTACK)); - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_atk, atk)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_atk_error); - return; - } - break; - case "em": - try { - int em = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - entity.setFightProperty(FightProperty.FIGHT_PROP_ELEMENT_MASTERY, em); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ELEMENT_MASTERY)); - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_em, em)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_em_error); - return; - } - break; - case "er": - try { - float er = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float erecharge = er / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, erecharge); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY)); - float iger = erecharge * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_er, iger)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_er_error); - return; - } - break; - case "crate": - try { - float cr = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float crate = cr / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, crate); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CRITICAL)); - float igcrate = crate * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_cr, igcrate)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_cr_error); - return; - } - break; - case "cdmg": - try { - float cdmg = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float cdamage = cdmg / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, cdamage); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CRITICAL_HURT)); - float igcdmg = cdamage * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_cd, igcdmg)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_cd_error); - return; - } - break; - case "epyro": - try { - float epyro = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float pyro = epyro / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_FIRE_ADD_HURT, pyro); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_FIRE_ADD_HURT)); - float igpyro = pyro * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_pdb, igpyro)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_pdb_error); - return; - } - break; - case "ecryo": - try { - float ecryo = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float cryo = ecryo / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_ICE_ADD_HURT, cryo); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ICE_ADD_HURT)); - float igcyro = cryo * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_cdb, igcyro)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_cdb_error); - return; - } - break; - case "ehydro": - try { - float ehydro = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float hydro = ehydro / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_WATER_ADD_HURT, hydro); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_WATER_ADD_HURT)); - float ighydro = hydro * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_hdb, ighydro)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_hdb_error); - return; - } - break; - case "eanemo": - try { - float eanemo = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float anemo = eanemo / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_WIND_ADD_HURT, anemo); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_WIND_ADD_HURT)); - float iganemo = anemo * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_adb, iganemo)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_adb_error); - return; - } - break; - case "egeo": - try { - float egeo = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float geo = egeo / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_ROCK_ADD_HURT, geo); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ROCK_ADD_HURT)); - float iggeo = geo * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_gdb, iggeo)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_gdb_error); - return; - } - break; - case "ethunder": - case "eelec": - try { - float eelec = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float elec = eelec / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_ELEC_ADD_HURT, elec); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ELEC_ADD_HURT)); - float igelec = elec * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_edb, igelec)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_edb_error); - return; - } - break; - case "ephys": - try { - float ephys = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float phys = ephys / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, phys); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT)); - float igphys = phys * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_physdb, igphys)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_physdb_error); - return; - } - break; - case "edend": - try { - float edend = Integer.parseInt(args.get(1)); - EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); - float dend = edend / 10000; - entity.setFightProperty(FightProperty.FIGHT_PROP_GRASS_ADD_HURT, dend); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_GRASS_ADD_HURT)); - float igdend = dend * 100; - CommandHandler.sendMessage(sender, String.format(Grasscutter.getLanguage().SetStats_set_ddb, igdend)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(sender, Grasscutter.getLanguage().SetStats_set_ddb_error); + int uid = Integer.parseInt(uidStr); + targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid); + if (targetPlayer == null) { + CommandHandler.sendMessage(sender, lang.SetStats_player_error); + return; + } + } catch (NumberFormatException e) { + CommandHandler.sendMessage(sender, lang.SetStats_uid_error); return; } + statStr = args.get(1).toLowerCase(); + valueStr = args.get(2); break; + }; + + EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); + + float value; + try { + if (valueStr.endsWith("%")) { + value = Float.parseFloat(valueStr.substring(0, valueStr.length()-1))/100f; + } else { + value = Float.parseFloat(valueStr); + } + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(sender, lang.SetStats_value_error); + return; + } + + + + if (stats.containsKey(statStr)) { + Stat stat = stats.get(statStr); + entity.setFightProperty(stat.prop, value); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); + if (stat.percent) { + valueStr = String.format("%.1f%%", value*100f); + } else { + valueStr = String.format("%.0f", value); + } + if (targetPlayer == sender) { + CommandHandler.sendMessage(sender, String.format(lang.SetStats_set_self, stat.name, valueStr)); + } else { + CommandHandler.sendMessage(sender, String.format(lang.SetStats_set_for_uid, stat.name, uidStr, valueStr)); + } + return; + } else { + CommandHandler.sendMessage(sender, usage); + return; } } }