diff --git a/docs/scarpet/api/Scoreboard.md b/docs/scarpet/api/Scoreboard.md index d2feb12d..0be72203 100644 --- a/docs/scarpet/api/Scoreboard.md +++ b/docs/scarpet/api/Scoreboard.md @@ -27,5 +27,80 @@ for the objective. ### `scoreboard_display(place, objective)` -sets display location for a specified `objective`. If `objective` is `null`, then display is cleared. If objective is invalid, +Sets display location for a specified `objective`. If `objective` is `null`, then display is cleared. If objective is invalid, returns `null`. + +# Team + +### `team_list()`, `team_list(team)` + +Returns all available teams as a list with no arguments. + +When a `team` is specified, it returns all the players inside that team. If the `team` is invalid, returns `null`. + +### `team_add(team)`, `team_add(team,player)` + +With one argument, creates a new `team` and returns its name if successful, or `null` if team already exists. + + +`team_add('admin')` -> Create a team with the name 'admin' +`team_add('admin','Steve')` -> Joing the player 'Steve' into the team 'admin' + +If a `player` is specified, the player will join the given `team`. Returns `true` if player joined the team, or `false` if nothing changed since the player was already in this team. If the team is invalid, returns `null` + +### `team_remove(team)` + +Removes a `team`. Returns `true` if the team was deleted, or `null` if the team is invalid. + +### `team_leave(player)` + +Removes the `player` from the team he is in. Returns `true` if the player left a team, otherwise `false`. + +`team_leave('Steve')` -> Removes Steve from the team he is currently in +`for(team_list('admin'), team_leave('admin', _))` -> Remove all players from team 'admin' + +### `team_property(team,property,value?)` + +Reads the `property` of the `team` if no `value` is specified. If a `value` is added as a third argument, it sets the `property` to that `value`. + +* `collisionRule` + * Type: String + * Options: always, never, pushOtherTeams, pushOwnTeam + +* `color` + * Type: String + * Options: See [team command](https://minecraft.gamepedia.com/Commands/team#Arguments) (same strings as `'teamcolor'` [command argument](https://github.com/gnembon/fabric-carpet/blob/master/docs/scarpet/Full.md#command-argument-types] options)) + +* `displayName` + * Type: String or FormattedText, when querying returns FormattedText + +* `prefix` + * Type: String or FormattedText, when querying returns FormattedText + +* `suffix` + * Type: String or FormattedText, when querying returns FormattedText + +* `friendlyFire` + * Type: boolean + +* `seeFriendlyInvisibles` + * Type: boolean + +* `nametagVisibility` + * Type: String + * Options: always, never, hideForOtherTeams, hideForOwnTeam + +* `deathMessageVisibility` + * Type: String + * Options: always, never, hideForOtherTeams, hideForOwnTeam + +Examples: + +``` +team_property('admin','color','dark_red') Make the team color for team 'admin' dark red +team_property('admin','prefix',format('r Admin | ')) Set prefix of all players in 'admin' +team_property('admin','display_name','Administrators') Set display name for team 'admin' +team_property('admin','seeFriendlyInvisibles',true) Make all players in 'admin' see other admins even when invisible +team_property('admin','deathMessageVisibility','hideForOtherTeams') Make all players in 'admin' see other admins even when invisible +``` + diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index 012ad76f..db4d0d7b 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -84,6 +84,11 @@ scoreboard scoreboard_add scoreboard_remove scoreboard_display +team_add +team_list +team_remove +team_leave +team_property see_sky set set_biome diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index cad62780..3ad710dc 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -60,6 +60,8 @@ scoreboard scoreboard_add scoreboard_remove scoreboard_display + team_add team_list team_remove team_leave team_property + player spawn entity_id entity_list entity_area entity_selector query modify entity_event entity_load_handler entity_types stack_limit item_category recipe_data crafting_remaining_item diff --git a/docs/scarpet/resources/editors/npp/scarpet_v1.7_notepad++.xml b/docs/scarpet/resources/editors/npp/scarpet_v1.7_notepad++.xml index ffb50e58..a24fe8f0 100644 --- a/docs/scarpet/resources/editors/npp/scarpet_v1.7_notepad++.xml +++ b/docs/scarpet/resources/editors/npp/scarpet_v1.7_notepad++.xml @@ -60,6 +60,8 @@ scoreboard scoreboard_add scoreboard_remove scoreboard_display + team_add team_list team_remove team_leave team_property + player spawn entity_id entity_list entity_area entity_selector query modify entity_event stack_limit item_category recipe_data crafting_remaining_item diff --git a/src/main/java/carpet/script/api/Scoreboards.java b/src/main/java/carpet/script/api/Scoreboards.java index fbce0245..821294ce 100644 --- a/src/main/java/carpet/script/api/Scoreboards.java +++ b/src/main/java/carpet/script/api/Scoreboards.java @@ -9,14 +9,20 @@ import carpet.script.value.ListValue; import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; +import carpet.script.value.FormattedTextValue; import carpet.script.value.Value; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ServerScoreboard; import net.minecraft.scoreboard.ScoreboardCriterion; import net.minecraft.scoreboard.ScoreboardObjective; import net.minecraft.scoreboard.ScoreboardPlayerScore; +import net.minecraft.scoreboard.Team; +import net.minecraft.scoreboard.AbstractTeam; import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import java.util.stream.Collectors; @@ -147,5 +153,249 @@ public class Scoreboards { scoreboard.setObjectiveSlot(slot, objective); return (_c, _t) -> new NumericValue(slot); }); + + expression.addLazyFunction("team_list", -1, (c, t, lv) -> + { + if(lv.size() > 1) throw new InternalExpressionException("'team_list' requires zero or one parameters"); + CarpetContext cc = (CarpetContext)c; + ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); + if(lv.size() == 0) { + Value ret = ListValue.wrap(scoreboard.getTeamNames().stream().map(StringValue::of).collect(Collectors.toList())); + return (_c, _t) -> ret; + } else if(lv.size() == 1) { + Team team = scoreboard.getTeam(lv.get(0).evalValue(c).getString()); + if(team == null) return LazyValue.NULL; + Value ret = ListValue.wrap(team.getPlayerList().stream().map(StringValue::of).collect(Collectors.toList())); + return (_c, _t) -> ret; + } else { + return LazyValue.NULL; + } + }); + + + expression.addLazyFunction("team_add", -1, (c, t, lv) -> + { + if(!(lv.size() < 3 && lv.size() > 0)) throw new InternalExpressionException("'team_add' requires one or two parameters"); + + CarpetContext cc = (CarpetContext)c; + ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); + String teamName = lv.get(0).evalValue(c).getString(); + + if(lv.size() == 1) { + if(scoreboard.getTeam(teamName) == null) { + scoreboard.addTeam(teamName); + Value ret = new StringValue(teamName); + return (_c, _t) -> ret; + } else { + return LazyValue.NULL; + } + } else if(lv.size() == 2) { + Value playerVal = lv.get(1).evalValue(c); + + String player = EntityValue.getPlayerNameByValue(playerVal); + if(player == null) return LazyValue.NULL; + + Team team = scoreboard.getTeam(teamName); + if(team == null) return LazyValue.NULL; + + if(team.isEqual(scoreboard.getPlayerTeam(player))) { + return LazyValue.FALSE; + } else { + scoreboard.addPlayerToTeam(player,scoreboard.getTeam(teamName)); + return LazyValue.TRUE; + } + } else { + return LazyValue.NULL; + } + }); + + expression.addLazyFunction("team_remove", 1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext)c; + ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); + Value teamVal = lv.get(0).evalValue(c); + + String team = teamVal.getString(); + + if(scoreboard.getTeam(team) != null) { + scoreboard.removeTeam(scoreboard.getTeam(team)); + return LazyValue.TRUE; + } else { + return LazyValue.NULL; + } + }); + + + expression.addLazyFunction("team_leave", 1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext)c; + ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); + Value playerVal = lv.get(0).evalValue(c); + + String player = EntityValue.getPlayerNameByValue(playerVal); + if(player == null) return LazyValue.NULL; + + Value ret = new NumericValue(scoreboard.clearPlayerTeam(player)); + return (_c, _t) -> ret; + }); + + expression.addLazyFunction("team_property", -1, (c, t, lv) -> + { + CarpetContext cc = (CarpetContext)c; + ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); + + if(lv.size() < 2 || lv.size() > 3) throw new InternalExpressionException("'team_property' requires two or three arguments"); + + Value teamVal = lv.get(0).evalValue(c); + Value propertyVal = lv.get(1).evalValue(c); + + Value settingVal = null; + boolean modifying = false; + if(lv.size() == 3) { + modifying = true; + settingVal = lv.get(2).evalValue(c); + } + + Team team = scoreboard.getTeam(teamVal.getString()); + if(team == null) return LazyValue.NULL; + + if(!(propertyVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the second argument"); + + switch (propertyVal.getString()) { + case "collision_rule": + if(!modifying) { + Value ret = new StringValue(team.getCollisionRule().name); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); + + AbstractTeam.CollisionRule collisionRule = AbstractTeam.CollisionRule.getRule(settingVal.getString()); + if(collisionRule == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); + team.setCollisionRule(collisionRule); + break; + case "color": + if(!modifying) { + Value ret = new StringValue(team.getColor().getName()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); + + Formatting color = Formatting.byName(settingVal.getString().toUpperCase()); + if(color == null || !color.isColor()) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); + team.setColor(color); + + break; + case "death_message_visibility": + if(!modifying) { + Value ret = new StringValue(team.getDeathMessageVisibilityRule().name); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); + + AbstractTeam.VisibilityRule deathMessageVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString()); + if(deathMessageVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); + team.setDeathMessageVisibilityRule(deathMessageVisibility); + + break; + case "display_name": + if(!modifying) { + Value ret = new FormattedTextValue(team.getDisplayName()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); + + Text displayName; + + if(settingVal instanceof FormattedTextValue) { + displayName = ((FormattedTextValue) settingVal).getText(); + } else { + displayName = new LiteralText(settingVal.getString()); + } + + team.setDisplayName(displayName); + + break; + case "friendly_fire": + if(!modifying) { + Value ret = new NumericValue(team.isFriendlyFireAllowed()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString()); + + boolean friendlyFire = settingVal.getBoolean(); + team.setFriendlyFireAllowed(friendlyFire); + break; + case "nametag_visibility": + if(!modifying) { + Value ret = new StringValue(team.getNameTagVisibilityRule().name); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); + + AbstractTeam.VisibilityRule nametagVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString()); + if(nametagVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); + team.setNameTagVisibilityRule(nametagVisibility); + + break; + case "prefix": + if(!modifying) { + Value ret = new FormattedTextValue(team.getPrefix()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property ' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); + + Text prefix; + + if(settingVal instanceof FormattedTextValue) { + prefix = ((FormattedTextValue) settingVal).getText(); + } else { + prefix = new LiteralText(settingVal.getString()); + } + + team.setPrefix(prefix); + break; + case "see_friendly_invisibles": + if(!modifying) { + Value ret = new NumericValue(team.shouldShowFriendlyInvisibles()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString()); + + boolean seeFriendlyInvisibles = settingVal.getBoolean(); + team.setShowFriendlyInvisibles(seeFriendlyInvisibles); + + break; + case "suffix": + if(!modifying) { + Value ret = new FormattedTextValue(team.getSuffix()); + return (_c, _t) -> ret; + } + + if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); + + Text suffix; + + if(settingVal instanceof FormattedTextValue) { + suffix = ((FormattedTextValue) settingVal).getText(); + } else { + suffix = new LiteralText(settingVal.getString()); + } + + team.setSuffix(suffix); + break; + default: + throw new InternalExpressionException("team property " + propertyVal.getString() + " is not a valid property"); + } + return LazyValue.TRUE; + }); } } + diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index 932499e9..e010c027 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -143,6 +143,28 @@ public class EntityValue extends Value return player; } + public static String getPlayerNameByValue(Value value) + { + String playerName = null; + if (value instanceof EntityValue) + { + Entity e = ((EntityValue) value).getEntity(); + if (e instanceof ServerPlayerEntity) + { + playerName = e.getEntityName(); + } + } + else if (value.isNull()) + { + return null; + } + else + { + playerName = value.getString(); + } + return playerName; + } + @Override public String getString() {