Loot, Shop & Rewards
A room's rewardType — set by the door the party walked through — decides what spawns in it once its mobs are cleared: artifacts, coins, or (for shop rooms, unconditionally) a shop offer. Reaching the final room or dying additionally spawns a reward chest. This page covers artifacts.yml, shop.yml, coins.yml, rewards.yml, and the reward carry-over back to the lobby.
Artifacts (artifacts.yml)
Key | Type | Description |
|---|---|---|
| string | Artifact id, looked up by |
| double | Relative weight for random selection when an |
| boolean | If |
|
| The display item. |
| component list | Lore/description lines shown above the artifact. |
| action list | Run against the claiming player when the artifact is selected. |
When a room's rewardType is ARTIFACTS, ArtifactService#spawnArtifacts spawns one artifact choice per participant, per REWARD position component in the room — each player sees their own independent draw (weighted by chance, excluding artifacts already marked unique and discovered by that player), with no duplicate artifact picked twice within the same draw for that player.
Selecting an artifact — ArtifactSelectEvent
Fully qualified name: com.astralrealms.tower.event.artifact.ArtifactSelectEvent (extends AbstractCancellableEvent).
Fired by ArtifactService#claimArtifact when a player interacts with one of their spawned artifact entities (via ArtifactsPacketListener). Cancellable — cancelling skips running the artifact's actions and leaves the artifact entity in place.
Field | Type | Description |
|---|---|---|
|
| The claiming player. |
|
| The tower instance. |
|
| The room the artifact was in. |
|
| The claimed artifact ( |
If not cancelled, the artifact's actions run against the player and every artifact entity spawned for that player in the room (RoomInstance#removeArtifactsForPlayer) is despawned and cleared — claiming one of several spawned choices discards the rest, it's not a per-entity removal.
Shop (shop.yml)
Key | Type | Description |
|---|---|---|
| map of artifact | Coin price for each artifact offered in shop rooms. Every key must match an |
| component list | Extra lore lines appended below each shop artifact's own description; |
Shop rooms (RoomType.SHOP) always spawn one offer per REWARD position component, chosen at random from offers without repeats within the room, and skip mob spawning entirely (setupRoom transitions a shop room straight to RoomPhase.REWARDS). Buying an offer (ShopService#buyShopOffer) checks the offer hasn't already been purchased (shop-already-purchased) and the player has enough %tower_coins% (shop-not-enough-points — see the messages warning), deducts the price from PlayerData.coins(), marks the offer purchased, and runs the artifact's actions.
Coins (coins.yml)
Key | Type | Description |
|---|---|---|
| double | Intended per-kill drop probability. |
| int | Inclusive range for how many coins a single mob-kill drop is worth. |
|
| The item used to represent dropped/rewarded coin stacks. |
| int | Total coin amount granted when a room's |
Coins are physical display entities (PacketItem) in the world; walking within 3.5 blocks despawns nearby piles and credits every participant's PlayerData.coins() with the summed amount (not just the picker-upper — coins are a shared/party resource). See Placeholders: %tower_coins%.
Room & end rewards (rewards.yml)
Key | Type | Description |
|---|---|---|
|
| Display item for the reward chest at that room index. |
| action list | Run against the claiming player when the chest is opened. |
| double | Weight used to pick between multiple entries under the same room index (only consulted if more than one entry exists for that index — a single entry is always used). |
RewardsConfiguration#getReward(roomIndex) picks (or weighted-randomly selects, if more than one entry exists for that index) the entry for a given room index. A reward chest is spawned (RoomService#spawnRewardsChests) whenever an instance ends with cause DEATH, or with COMPLETED on the instance's last room — right-clicking it (RewardListener) marks that player as having claimed it, plays a totem effect, sends room-reward (or completion-reward on the last room, with <room> = the room index), and queues the chest's actions for carry-over. Disconnecting from a tower instance before claiming a chest queues that room's reward automatically (RewardListener#onQuit) so players don't lose it by leaving.
Once every participant has claimed the room's reward chest, the instance is destroyed (InstanceService#endInstance(instance, EndCause.COMPLETED), checked 5 ticks after the last claim).
Reward carry-over
Rewards are never granted directly inside the tower; they accumulate as CachedRewards (a PaperAction string list + the room index they were earned at) in a 14-day-TTL Redis-backed cache (RewardService, keyed tower:rewards/tower:player_rewards:<uuid>), and are claimed back on the lobby:
Claiming a room-reward or end-of-run chest (or quitting before claiming) calls
RewardService#cacheReward(playerId, CachedRewards), which stores the entry and links it to the player.On the lobby, once AstralSync fires
PlayerDataLoadedEventfor the returning player, the bridge'sRewardsListenerreads every cached reward for that player (findRewardsByPlayer), runs each entry's action list against the player from the console (PaperActionFactory), fires aTowerFinishedEventper reward, deletes the cache entry (RewardService#deleteReward), logs atower_instance_finishedanalytics event, and finally deducts one daily ticket from the player'sTowerPlayerDatafor each reward whose room index is≥ 1(the lobby room, index0, doesn't consume a ticket).
TowerFinishedEvent
Fully qualified name: com.astralrealms.tower.bridge.event.TowerFinishedEvent (extends AbstractEvent, bridge module).
Fired by RewardsListener once per claimed CachedRewards entry being processed on the lobby. Not cancellable — notification only, after the reward's actions have already run.
Field | Type | Description |
|---|---|---|
|
| The player whose reward was just processed. |
|
| The room index the reward was earned at. |