Skip to content

Commit 132e237

Browse files
committed
feat: healpool and traps
1 parent c0337d7 commit 132e237

File tree

14 files changed

+437
-10
lines changed

14 files changed

+437
-10
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2025 ScreamingSandals
3+
*
4+
* This file is part of Screaming BedWars.
5+
*
6+
* Screaming BedWars is free software: you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Screaming BedWars is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with Screaming BedWars. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package org.screamingsandals.bedwars.api.events;
21+
22+
import org.jetbrains.annotations.ApiStatus;
23+
import org.jetbrains.annotations.NotNull;
24+
import org.screamingsandals.bedwars.api.BedwarsAPI;
25+
import org.screamingsandals.bedwars.api.Team;
26+
import org.screamingsandals.bedwars.api.game.LocalGame;
27+
import org.screamingsandals.bedwars.api.player.BWPlayer;
28+
29+
import java.util.function.Consumer;
30+
31+
@ApiStatus.NonExtendable
32+
public interface TrapTriggeredEvent extends BWCancellable {
33+
@NotNull LocalGame game();
34+
35+
@NotNull BWPlayer player();
36+
37+
@NotNull Team owningTeam();
38+
39+
// TODO: potion effect (add type to api-utils)
40+
41+
boolean affectsTeamMembers();
42+
43+
boolean affectsEnemies();
44+
45+
boolean singularUse();
46+
47+
double detectionRange();
48+
49+
static void handle(@NotNull Object plugin, @NotNull Consumer<@NotNull TrapTriggeredEvent> consumer) {
50+
BedwarsAPI.getInstance().getEventUtils().handle(plugin, TrapTriggeredEvent.class, consumer);
51+
}
52+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (C) 2025 ScreamingSandals
3+
*
4+
* This file is part of Screaming BedWars.
5+
*
6+
* Screaming BedWars is free software: you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Screaming BedWars is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with Screaming BedWars. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package org.screamingsandals.bedwars.events;
21+
22+
import lombok.Data;
23+
import lombok.Setter;
24+
import lombok.experimental.Accessors;
25+
import lombok.experimental.Tolerate;
26+
import org.jetbrains.annotations.NotNull;
27+
import org.jetbrains.annotations.Unmodifiable;
28+
import org.screamingsandals.bedwars.api.events.TrapTriggeredEvent;
29+
import org.screamingsandals.bedwars.game.GameImpl;
30+
import org.screamingsandals.bedwars.game.TeamImpl;
31+
import org.screamingsandals.bedwars.player.BedWarsPlayer;
32+
import org.screamingsandals.lib.event.CancellableEvent;
33+
import org.screamingsandals.lib.item.meta.PotionEffect;
34+
35+
import java.util.List;
36+
37+
@Data
38+
@Accessors(fluent = true, chain = false)
39+
public class TrapTriggeredEventImpl implements TrapTriggeredEvent, CancellableEvent {
40+
private final @NotNull GameImpl game;
41+
private final @NotNull BedWarsPlayer player;
42+
private final @NotNull TeamImpl owningTeam;
43+
private final @Unmodifiable @NotNull List<@NotNull PotionEffect> potionEffect;
44+
private final boolean affectsTeamMembers;
45+
private final boolean affectsEnemies;
46+
private final boolean singularUse;
47+
private final double detectionRange;
48+
private boolean cancelled;
49+
50+
@Override
51+
public boolean isCancelled() {
52+
return cancelled;
53+
}
54+
55+
@Override
56+
public void setCancelled(boolean cancelled) {
57+
this.cancelled = cancelled;
58+
}
59+
}

plugin/common/src/main/java/org/screamingsandals/bedwars/game/GameCycleImpl.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
package org.screamingsandals.bedwars.game;
2121

2222
import lombok.RequiredArgsConstructor;
23+
import org.jetbrains.annotations.NotNull;
2324
import org.screamingsandals.bedwars.api.config.GameConfigurationContainer;
2425
import org.screamingsandals.bedwars.api.events.TargetInvalidationReason;
2526
import org.screamingsandals.bedwars.api.game.Game;
2627
import org.screamingsandals.bedwars.api.game.GameCycle;
2728
import org.screamingsandals.bedwars.api.game.GameStatus;
29+
import org.screamingsandals.bedwars.api.game.target.TargetBlock;
2830
import org.screamingsandals.bedwars.boss.BossBarImpl;
2931
import org.screamingsandals.bedwars.commands.StatsCommand;
3032
import org.screamingsandals.bedwars.config.GameConfigurationContainerImpl;
@@ -48,6 +50,7 @@
4850
import org.screamingsandals.bedwars.utils.TitleUtils;
4951
import org.screamingsandals.lib.Server;
5052
import org.screamingsandals.lib.event.EventManager;
53+
import org.screamingsandals.lib.item.meta.PotionEffectType;
5154
import org.screamingsandals.lib.lang.Message;
5255
import org.screamingsandals.lib.spectator.Component;
5356
import org.screamingsandals.lib.spectator.bossbar.BossBarColor;
@@ -56,6 +59,7 @@
5659
import org.screamingsandals.lib.tasker.Tasker;
5760
import org.screamingsandals.lib.tasker.TaskerTime;
5861
import org.screamingsandals.lib.tasker.task.Task;
62+
import org.screamingsandals.lib.world.Location;
5963
import org.screamingsandals.lib.world.gamerule.GameRuleType;
6064

6165
import java.util.ArrayList;
@@ -158,6 +162,7 @@ private void rebuildGameArena(GameChangedStatusEventImpl statusE) {
158162
private void tickRunningGame(GameChangedStatusEventImpl statusE, GameTickEventImpl tick) {
159163
var runningTeams = game.getTeamsAlive();
160164
updateExpirableTargetBlocks(runningTeams);
165+
processTraps(runningTeams);
161166

162167
var players = game.getPlayers();
163168
var teamsInGame = game.getTeamsInGame();
@@ -331,6 +336,74 @@ private void updateExpirableTargetBlocks(List<TeamImpl> runningTeams) {
331336
}
332337
}
333338

339+
private void processTraps(@NotNull List<@NotNull TeamImpl> teams) {
340+
for (var team : teams) {
341+
var target = team.getTarget();
342+
Location location;
343+
if (target instanceof TargetBlock) {
344+
location = ((TargetBlock) target).getTargetBlock().as(Location.class);
345+
} else {
346+
// this team does not have locatable target, we have to use one of the spawns
347+
location = team.getTeamSpawns().get(0);
348+
}
349+
350+
for (var trap : List.copyOf(team.getTraps())) {
351+
var squared = trap.getDetectionRange() * trap.getDetectionRange();
352+
353+
var stream = game.getConnectedPlayers().stream()
354+
.filter(player -> !player.isSpectator());
355+
if (trap.isEnemies() && !trap.isTeam()) {
356+
stream = stream.filter(player -> !team.isPlayerInTeam(player));
357+
} else if (!trap.isEnemies() && trap.isTeam()) {
358+
stream = stream.filter(team::isPlayerInTeam);
359+
}
360+
stream.filter(player -> location.getDistanceSquared(player.getLocation()) <= squared)
361+
.forEach(player -> {
362+
var event = new TrapTriggeredEventImpl(game, player, team, trap.getEffects(), trap.isTeam(), trap.isEnemies(), trap.isSingularUse(), trap.getDetectionRange());
363+
EventManager.fire(event);
364+
365+
if (event.cancelled()) {
366+
return;
367+
}
368+
369+
player.addPotionEffects(trap.getEffects());
370+
371+
if (trap.isSingularUse()) {
372+
team.getTraps().remove(trap);
373+
}
374+
375+
// TODO: invisible players? removing invisibility?
376+
377+
if (trap.getName() != null) {
378+
if (trap.getMessage() != null) {
379+
player.sendMessage(
380+
Message.ofRichText(trap.getMessage())
381+
.prefix(game.getCustomPrefixComponent())
382+
.placeholder("team", Component.text(team.getName(), team.getColor().getTextColor()))
383+
.placeholder("trap", trap.getName())
384+
);
385+
}
386+
387+
if (trap.getTeamTitle() != null) {
388+
var title = Message
389+
.ofRichText(trap.getTeamTitle())
390+
.joinRichText(trap.getTeamSubtitle() != null ? trap.getTeamSubtitle() : "")
391+
.placeholder("trap", trap.getName())
392+
.times(TitleUtils.defaultTimes());
393+
394+
team.getPlayers().forEach(pl -> pl.showTitle(title));
395+
}
396+
397+
var triggerSound = trap.getTriggerSound();
398+
if (triggerSound != null) {
399+
team.getPlayers().forEach(pl -> pl.playSound(triggerSound));
400+
}
401+
}
402+
});
403+
}
404+
}
405+
}
406+
334407
private void prepareGame(GameChangedStatusEventImpl statusE, GameTickEventImpl tick) {
335408
var configurationContainer = game.getConfigurationContainer();
336409
Debug.info(game.getName() + ": preparing game");

plugin/common/src/main/java/org/screamingsandals/bedwars/game/TeamImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.screamingsandals.bedwars.game.target.AExpirableTarget;
3232
import org.screamingsandals.bedwars.game.target.TargetBlockImpl;
3333
import org.screamingsandals.bedwars.game.upgrade.UpgradableImpl;
34+
import org.screamingsandals.bedwars.game.upgrade.builtin.TrapUpgradeDefinition;
3435
import org.screamingsandals.bedwars.lang.LangKeys;
3536
import org.screamingsandals.bedwars.player.BedWarsPlayer;
3637
import org.screamingsandals.lib.api.types.server.LocationHolder;
@@ -75,6 +76,7 @@ public class TeamImpl extends UpgradableImpl implements Team {
7576
private Hologram protectHologram;
7677
private final Random randomSpawn = new Random();
7778
private boolean forced = false;
79+
private final @NotNull List<@NotNull TrapUpgradeDefinition> traps = new ArrayList<>();
7880

7981
public void start() {
8082
if (started) {
@@ -161,6 +163,7 @@ public void start() {
161163
this.teamChestInventory = Objects.requireNonNull(ContainerFactory.createContainer(InventoryType.of("ender_chest"), message));
162164
syncBuiltInUpgrades(game.getGameVariant().getUpgrades());
163165
resetUpgrades();
166+
this.traps.clear();
164167
this.started = true;
165168
}
166169

@@ -183,6 +186,7 @@ public void destroy() {
183186
chests.clear();
184187
players.clear();
185188
teamMembers.clear();
189+
this.traps.clear();
186190
started = false;
187191
forced = false;
188192
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2025 ScreamingSandals
3+
*
4+
* This file is part of Screaming BedWars.
5+
*
6+
* Screaming BedWars is free software: you can redistribute it and/or modify it
7+
* under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Screaming BedWars is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with Screaming BedWars. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package org.screamingsandals.bedwars.game.upgrade.builtin;
21+
22+
import org.jetbrains.annotations.NotNull;
23+
import org.screamingsandals.bedwars.events.UpgradeLevelChangedEventImpl;
24+
import org.screamingsandals.bedwars.game.TeamImpl;
25+
import org.screamingsandals.lib.event.OnEvent;
26+
import org.screamingsandals.lib.utils.annotations.Service;
27+
28+
@Service
29+
public class TrapEffectUpgradeHandler {
30+
@OnEvent
31+
public void handle(@NotNull UpgradeLevelChangedEventImpl event) {
32+
if (!(event.getUpgradable() instanceof TeamImpl)) {
33+
return;
34+
}
35+
36+
var team = (TeamImpl) event.getUpgradable();
37+
var builtin = event.getGame().getGameVariant().getUpgrade(event.getName());
38+
39+
if (!(builtin instanceof TrapUpgradeDefinition)) {
40+
return;
41+
}
42+
43+
var level = event.getNewLevel();
44+
if (level < 1) {
45+
return;
46+
}
47+
48+
if (!team.getTraps().contains((TrapUpgradeDefinition) builtin)) {
49+
team.getTraps().add((TrapUpgradeDefinition) builtin);
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)