diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml new file mode 100644 index 000000000..2b42a1482 --- /dev/null +++ b/.github/workflows/deploy-release.yml @@ -0,0 +1,24 @@ +name: Maven deploy release +on: + release: + types: + - published + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Maven settings + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: eredrim + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + + - name: Deploy the package + run: mvn --batch-mode deploy -DaltDeploymentRepository="eredrim::default::https://repo.eredrim.fr/repository/maven-releases/" + env: + MAVEN_USERNAME: ${{ secrets.MVN_USER }} + MAVEN_PASSWORD: ${{ secrets.MVN_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/deploy-snapshot.yml b/.github/workflows/deploy-snapshot.yml new file mode 100644 index 000000000..585220e2f --- /dev/null +++ b/.github/workflows/deploy-snapshot.yml @@ -0,0 +1,55 @@ +name: Maven deploy snapshot +on: + push: + branches: + - master + +jobs: + deploy: + if: "!contains(github.event.head_commit.message, '[release]') && !contains(github.event.head_commit.message, '[doc]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Maven settings + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: eredrim + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + + - name: Get project version number + run: | + mvn_version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "mvn_version=${mvn_version}" >> $GITHUB_ENV + + - name: Check if version already exists on repository + run: | + http_code=$(curl -s -o /dev/null -w "%{http_code}" https://repo.eredrim.fr/repository/maven-snapshots/net/slipcor/pvparena/${{ env.mvn_version }}/maven-metadata.xml) + echo "version_http_code=${http_code}" >> $GITHUB_ENV + + - name: Calculate build version with metadata + if: ${{ env.version_http_code == 200 }} + run: | + curl https://repo.eredrim.fr/repository/maven-snapshots/net/slipcor/pvparena/${{ env.mvn_version }}/maven-metadata.xml -o metadata.xml + build_number=$(grep -oP '(?<=buildNumber>)[^<]+' "metadata.xml") + echo "build_version=$((build_number + 1))" >> $GITHUB_ENV + + - name: Generate a new build version + if: ${{ env.version_http_code != 200 }} + run: echo "build_version=1" >> $GITHUB_ENV + + - name: Deploy the package + run: mvn --batch-mode deploy -DbuildVersion=-b${{ env.build_version }} -DaltDeploymentRepository="eredrim::default::https://repo.eredrim.fr/repository/maven-snapshots/" + env: + MAVEN_USERNAME: ${{ secrets.MVN_USER }} + MAVEN_PASSWORD: ${{ secrets.MVN_PASSWORD }} + + - name: Post discord notification + run: | + commits=`echo "${{ join(github.event.commits.*.message, '\n - ') }}" | tr '\n' ' '` + avatar_url=https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png + bot_username="Build notification" + payload_json='{ "username": "'$bot_username'", "avatar_url": "'$avatar_url'", "content": "A new dev build of PVP arena is available! Download it by saving the attached file.", "embeds": [{"description": ":spiral_note_pad: **New commits:**\n\n - '$commits'"}] }' + curl -X POST ${{ secrets.DISCORD_WEBHOOK_URL }} -F payload_json="${payload_json}" + curl -X POST ${{ secrets.DISCORD_WEBHOOK_URL }} -F username="${bot_username}" -F avatar_url="${avatar_url}" -F file=@target/pvparena-${{ env.mvn_version }}-b${{ env.build_version }}.jar \ No newline at end of file diff --git a/.gitignore b/.gitignore index ae4d08a55..c76adf957 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # Maven target/ +dependency-reduced-pom.xml /bin/ diff --git a/doc/changelog.md b/doc/changelog.md deleted file mode 100644 index 1fb81cb99..000000000 --- a/doc/changelog.md +++ /dev/null @@ -1,347 +0,0 @@ -- v1.3.4.298 - attempt to properly back up NBT data of player's items in case of an unnatural leaving of the arena - -- v1.3.4.297 - address github issue #351 - add yet another delay to fix Spigot -- v1.3.4.296 - address github issue #329 - actually change the scoreboard title :O -- v1.3.4.295 - fix the fact that the scoreboard did not update on losing the last life. Thanks to @Oruss7 -- v1.3.4.294 - add team size and total team count when joining -- v1.3.4.293 - address github issue #332 - display first checkpoint message, and display numbers starting from 1 -- v1.3.4.292 - address github issue #329 - use arena prefix instead of name, if still too long, shorten manually -- v1.3.4.291 - added debug to PotionSplashEvent for someone to have evidence to report a bug -- v1.3.4.290 - when setting up a region, check that it has actual resulting volume before saving -- v1.3.4.289 - address github issue #324 - call home asynchronously -- v1.3.4.288 - stop igniting your own TNT - and tell people that it is not okay -- v1.3.4.287 - update EventActions docs to properly reflect the node names -- v1.3.4.286 - update EventActions docs and fix github issue #314 by not stopping arenas twice on reload! -- v1.3.4.285 - allow to update spawn and blocks on the fly -- v1.3.4.284 - fix docs [remove colorteams and scoreboard] and add language and docs for BetterClass "respawnCommand" -- v1.3.4.283 - add EventActions addition (classchange hook) -- v1.3.4.282 - address github issue #305 - check max health before setting health -- v1.3.4.281 - address github issue #302 - prevent NPE for spectators when joining the arena -- v1.3.4.280 - remove debug output of time message nodes -- v1.3.4.279 - add github issue #249 - playSound (???) to add particle effect, DONE -- v1.3.4.278 - add github issue #124 - add timer configs to add/remove/change timer interval messages -- v1.3.4.277 - add github issue #117 - BossBar for Domination -- v1.3.4.276 - do not setup a scoreboard if spectating is cancelled/not possible -- v1.3.4.275 - allow right clicking blocks when LOST attempt 2 -- v1.3.4.274 - allow right clicking blocks when LOST and add Region Protection Tutorial -- v1.3.4.273 - update player equip function to support offhand slots -- v1.3.4.272 - properly protect and not overprotect, affected: MOBS [block lightning], TNT [prevent entity damage], GROW [actually block block growth] -- v1.3.4.271 - remove metrics and update the readme with new region shape tutorial -- v1.3.4.270 - do not add spectator names to the scoreboard -- v1.3.4.269 - update the spectator scoreboard -- v1.3.4.268 - create a scoreboard for spectators -- v1.3.4.267 - address github issue #291 by adding "perms.spectatorinteract" to allow spectators to interact -- v1.3.4.266 - remove debug and address github issue #292 by checking if a player already joined an arena before doing anything -- v1.3.4.265 - how I miss those debug times. IS THE PLAYER FLYING OR NOT!??!! -- v1.3.4.264 - why not try without delay? -- v1.3.4.263 - change fly mode saving and restoring -- v1.3.4.262 - do not restore flying state if specating on death -- v1.3.4.261 - delay flying mode setting by 5 ticks when restoring a player -- v1.3.4.260 - address github issue #290 - catch NPE about Spawn Eggs -- v1.3.4.259 - finish off github issue #280 by adding a proper message about reloading the languages -- v1.3.4.258 - finish the fix for issue #198 by supporting beacon block definitions -- v1.3.4.257 - address github issue #198 - make particle circle function goal independant -- v1.3.4.256 - address github issue #285 - catch NPE by checking for missing round argument -- v1.3.4.255 - address github issue #263 - properly cancel interact event - I assumed that they come uncancelled - wrong -- v1.3.4.254 - who ordered .lck files? Not me! Byebye! [debugging file handler not closed] -- v1.3.4.253 - hotfix about cancelling PlayerItemConsumeEvent - sorry @mibby, fasting is over now! -- v1.3.4.252 - fix issue #263 by cancelling PlayerItemConsumeEvent - since when is this a necessity? The interact event was cancelled :P -- v1.3.4.251 - fix spawn alignment glitches, some of which were fixed by restarting the server, fix double messages around right clicking -- v1.3.4.250 - update some things to the latest API - fix CheckPoints spawn set logic, fix PlayerDeathMatch required kill display -- v1.3.4.249 - update to Spigot 1.11 - address github issue #218 -- v1.3.3.248 - /pa reload ymls | reload main config, language and help ymls -- v1.3.3.247 - do not duplicate offhand items and don't try to set objectives that are not needed (because of disabled scoreboard) -- v1.3.3.246 - address github issue #280, reload global language and help nodes on /pa reload -- v1.3.3.245 - revert player names appearing on scoreboards, maybe properly display 0 team lives left? -- v1.3.3.244 - catch an NPE about scoreboards and dead/offline players and fix a scoreboard crash vulnerability -- v1.3.3.243 - eventually delay scoreboard display to arena start, delay inventory reset to when a player gets put back to their exit spawn, delay fire tick reset -- v1.3.3.242 - properly reset scoreboard when simply leaving by command -- v1.3.3.241 - address github issue #278 - support "hand" placeholder for multiple-item-definitions too -- v1.3.3.240 - address github issue #276 by catching the NPE even deeper -- v1.3.3.239 - fix inventory double drop bug when losing the last life -- v1.3.3.238 - allow for default death messaeges by setting both deathmessage config nodes to false -- v1.3.3.237 - address github issue #271 - do not remove/use player list scoreboard if scoreboard is disabled -- v1.3.3.236 - address github issue #273 - add Elytra to chestplate definition list -- v1.3.3.235 - address github issue #274 - fix player leaving handling in general -- v1.3.3.234 - properly require permission for /pa command -- v1.3.3.233 - address github issue #273 - single item definitions (maybe more) gets lost until restart -- v1.3.3.232 - add github issue #258 - liberation scoreboard separation of jailed players -- v1.3.3.231 - add github issue #198 - particle display of domination claim radius -- v1.3.3.230 - add github issue #237 - items on kill, settable via command and "inventory" handle! -- v1.3.3.229 - address github issue #254 - update Arrow Hack for Spigot > 1.9 -- v1.3.3.228 - address github issue #151 and try to add a custom scoreboard entry to show round progress -- v1.3.3.227 - fix scoreboard removal and fix a bug that caused doubled starting method call -- v1.3.3.226 - allow longer scoreboard entries (48 characters for now) -- v1.3.3.225 - reintroduce custom scoreboard entries -- v1.3.3.224 - address github issue #264 - ArenaClass equipping debug triggers NPE -- v1.3.3.223 - address github issue #267 - critical fix about gamemodes -- v1.3.3.222 - fix grabbing the flag giving you no wool head -- v1.3.3.221 - refresh debug instance for global debug when stopping / changing debug output -- v1.3.3.220 - further ID fixes, and fix a but about GameMode setting and one about players being able to join an arena when it is restoring -- v1.3.3.219 - finish the item ID burial -- v1.3.3.218 - stop supporting item IDs in configs - configs shall be updated! -- v1.3.3.217 - do not nag people to update if updater type DOWNLOAD is selected - addresses github issue #244 -- v1.3.3.216 - address a bug about invisibility being nullified by internal scoreboard -- v1.3.3.215 - address issue #238 by adding refillCustomInventory - defaulting to true -- v1.3.3.214 - address issue #255 - Remove arrows stuck to everyone -- v1.3.3.213 - address issue #256 - Exception about ScoreBoards when shutting down -- v1.3.3.212 - fix issue #252 by catching a NPE -- v1.3.3.211 - revert c67e4a6 - never mess with flying speed or walking speed again plz :P -- v1.3.3.210 - revert 4f75803 - never mess with flying speed or walking speed again plz :P -- v1.3.3.209 - final attempt to get rid of the speed issue - deactivate with -10 -- v1.3.3.208 - address issues with commit 4f75803 -- v1.3.3.207 - address github issues #245 and #248 -- v1.3.3.206 - finish the spawn region fix -- v1.3.3.205 - continue attemmpt to fix region spawning -- v1.3.3.204 - revert the last commit and try to fix region spawning -- v1.3.3.203 - try to fix an issue about respawning players not getting reset properly -- v1.3.3.202 - try to finish off github issue #212 by delaying scoreboard slot selection and player removal -- v1.3.3.201 - allow to disable all gamemode changes; make "takeOutOfGame" actually work -- v1.3.3.200 - prevent the plugin from messing up player restoring in certain reset cases -- v1.3.3.199 - address github issue #238 - allow to keep ALL items on respawn -- v1.3.3.198 - add "teleportonkill" to allow force respawn of killers -- v1.3.3.197 - address github issue #238 - allow to keep ALL items on respawn -- v1.3.3.196 - address github issue #240 - message consistency -- v1.3.3.195 - address github issue #241 - don't use Location, use Vectors for offset -- v1.3.3.194 - fix github issue #232 - Potions disappearing when readying up -- v1.3.3.193 - fix StatisticsManager to actually be persistent. SORRY! -- v1.3.3.192 - add config for github issue #220 -- v1.3.3.191 - fix github issue #188 - I found the right way to deactivate collision -- v1.3.3.190 - address github issue #120 - limiting class changes -- v1.3.3.189 - address github issue #99 - can we finally bury this? ^^ -- v1.3.3.188 - [FFA] allow to punish being killed by other things than a player: punishsuicide -- v1.3.3.187 - allow to set keepOnRespawn to "all" to, yes, keep all items -- v1.3.3.186 - implement ColorTeams and ScoreBoards modules into core - addresses github issue #212 -- v1.3.3.185 - add an announcement verification hack to WarmupJoin -- v1.3.3.184 - revert build #177 (saturation lock), does not work anyways -- v1.3.3.183 - very important module fix - player resetting was broken! -- v1.3.3.182 - reduce command whitelist case sensitivity -- v1.3.3.181 - reduce command case sensitivity -- v1.3.3.180 - allow modules to know whether to soft reset a player -- v1.3.3.179 - fix config node typo -- v1.3.3.178 - allow to quick leave with caps lock -- v1.3.3.177 - add saturation lock, to prevent regains going crazy -- v1.3.3.176 - apply global and specific teleport offset when resetting player -- v1.3.3.175 - fix github issue #230 -- v1.3.3.174 - little thing about #230 and add more debug to see why it might not work yet -- v1.3.3.173 - address github issue #222, again -- v1.3.3.172 - finish github issue #225 -- v1.3.3.171 - add github issue #230 - apply the teleport protection to the lounge, too, to prevent teleport warnings -- v1.3.3.170 - try to fix disabling breaking arena shortcut rotation -- v1.3.3.169 - maybe fix an issue that shortcut rotation doesn't work when the arenas are disabled at start -- v1.3.3.168 - partially revert breaking #222 even more -- v1.3.3.167 - address github issue #227 - reset killer's items to KILLER's class -- v1.3.3.166 - maybe finally tackle github issue #222 -- v1.3.3.165 - properly implement github issue #225 -- v1.3.3.164 - finish up github issue #203 -- v1.3.3.163 - address github issue #224 -- v1.3.3.162 - address all remnants of issue #203 -- v1.3.3.161 - address github issue #224 - double output in the lounge -- v1.3.3.160 - I got an idea, how about we actually implement issue #188 ?! oh and add issue #225 -- v1.3.3.159 - address github issue #222 -- v1.3.3.158 - continue fixing the issue mentioned in build #153 -- v1.3.3.157 - address github issue #222, again -- v1.3.3.156 - change the updating process and block installing/updating when there is no install.yml due to "update.files" (you can allow this setting and disable automatic updates with updatemode "none" or "announce") -- v1.3.3.155 - remove spectral arrows from the potion meta list, those don't seem to have potion effects -- v1.3.3.153 - try to fix the issue of lounge players not being able to interact where they should -- v1.3.3.152 - try to implement github issue #188 -- v1.3.3.151 - add config setting for github issue #188 -- v1.3.3.150 - address github issue #131 - if it's not fixed, I at least added debug -- v1.3.3.149 - address github issue #215 by removing a never launched minigame API and make sure to get the proper shortcut name, if possible -- v1.3.3.148 - finally fix github issue #205 -- v1.3.3.147 - prevent inventory dropping even if custom class is active -- v1.3.3.146 - found the little bug that caused github issue #205 ! -- v1.3.3.145 - partially revert d8d9bf174027aadc6ccd641b6cef7b660f435f25 to address github issue #205 -- v1.3.3.144 - potions are operational. Please update your class definitions (if you did not use class chests) -- v1.3.3.143 - please use the same logic for saving and loading -- v1.3.3.142 - potions should work now. Please redo all your potionish classes (potions, splash potions, lingering, arrows, etc) -- v1.3.3.141 - try to fix armor supply -- v1.3.3.140 - properly fix Potion creation/saving broken by Spigot 1.9 API changes -- v1.3.3.139 - properly fix Inventory handling broken by Spigot 1.9 API changes -- v1.3.3.138 - move to Spigot 1.9.4 -- v1.3.2.137 - address github issue #205 -- v1.3.2.136 - add language response for ChestFiller -- v1.3.2.135 - add documentation about ChestFiller changes, add some more config nodes that are now properly loaded with defaults automatically -- v1.3.2.134 - address github issue #201 - properly call PAJoinEvent, this never was implemented correctly. Sorry! -- v1.3.2.133 - prepare ChestFiller addition by adding language and documentation -- v1.3.2.132 - prepare ChestFiller addition by adding config node -- v1.3.2.131 - remove FallingAnvils hooks and documentation - it did not work out :/ -- v1.3.2.130 - stop spamming, please. Aims at fixing github issue #154 -- v1.3.2.129 - address github issue #209 - oups -- v1.3.2.128 - add a module method "parseStartCountDown" to possibly override the remaining seconds to go -- v1.3.2.127 - fix github issue #204 by removing all traces of the nonexisting command "import" -- v1.3.2.126 - address github issue #202 - remove "error" and only write it to debug -- v1.3.2.125 - address github issue #155, prevent double dropping of inventory. Hope this does not break anything :P -- v1.3.2.124 - address github issue #154 - just remove tick 4, it's not that important anyways. And remove the blocklist spam :) -- v1.3.2.122 - furthermore fix the uninstall routine -- v1.3.2.121 - address github issue #131 - I think I found the bug! -- v1.3.2.120 - address github issue #203 by firstly fixing the NPE and adding more info to the uninstalling error (Main server log!) -- v1.3.2.119 - prevent double instantiation of arenas - use with caution! :P -- v1.3.2.118 - [CheckPoints] - address github issue #197 -- v1.3.2.117 - [BetterFight] add config setting to restrict explosions only to one-hit deaths -- v1.3.2.116 - add CheckPoint goal (github issue #184) - have fun testing! -- v1.3.2.115 - add "refillforkill" - restocks the inventory with the class items -- v1.3.2.114 - address github issue #191 - prevent NPE due to NULL item in class items -- v1.3.2.113 - add more debug to investigate fire charge ignition issues -- v1.3.2.112 - continue fix for Scoreboards being double reset in modules -- v1.3.2.111 - prepare fix for Scoreboards being double reset in modules -- v1.3.2.110 - address github issue #185 by fixing WorldEdit documentation and messages -- v1.3.2.109 - address github issue #186 -- v1.3.2.107 - address github issue #178 - prevent enderpearl teleport when not alive and fighting -- v1.3.2.106 - [TeamDeathMatch] fix a double broadcast of the winning team -- v1.3.2.105 - fix the documentation for EventAction config -- v1.3.2.103 - furthermore attempt to fix #175 by adding a teleport lock variable -- v1.3.2.102 - support multiple WATCH and LOUNGE regions - addresses github issue #175 -- v1.3.2.101 - finish github issue #174 -- v1.3.2.100 - address github issue #174 -- v1.3.2.99 - add Beacons settings and documentation -- v1.3.2.97 - add Titles API hooks, documentation will follow -- v1.3.2.96 - add a configuration node to change the schematics folder for WorldEdit - adds github issue #129 -- v1.3.2.95 - add region command documentation - thanks @Oruss7 -- v1.3.2.94 - add Language for special Duel/Vault hooking -- v1.3.2.93 - add config settings and documentation for the FallingAnvils module -- v1.3.2.92 - [forcewin] how about we load the command so it can be used? -- v1.3.2.91 - add /pa [arena] forcewin, shorthand !fw - forces a player / team to win -- v1.3.2.90 - fix some more errors about the new command. Works now :) -- v1.3.2.89 - fix the shorthand and the doc linking -- v1.3.2.88 - add /pa [arena] classchest [class] - shorthand !cc - fixed class chests containing the items -- v1.3.2.87 - address github issue #168, NPE on StructureGrowEvent -- v1.3.2.85 - revert deprecation of ArenaModule.getArena() - failsafe(r) loading of modules and goals - arenas will not appear lost any more! -- v1.3.2.84 - address github issue #161, properly read ambiguous ready block definition -- v1.3.2.83 - address github issue #159 - do not instanciate the tracker if disabled -- v1.3.2.82 - address github issue #158 by adding 'shortcut_shuffle' -- v1.3.2.81 - address github issue #154, maybe even issue #86 - only check necessarily flagged regions and BATTLE regions, with include-check -- v1.3.2.80 - properly fix build #68 -- v1.3.2.79 - add TELEPORT protection to allow teleport prevention (it was silently allowed if only happening IN the region, without command) -- v1.3.2.78 - change WALLS config setting command to "wallseconds", it interfered with the most probable arena name -- v1.3.2.77 - revert the CommandPreProcessEvent and rather fix the underlying problem, the command whitelist being too greedy. Added a config setting to use comand list as wildcards -- v1.3.2.76 - enforce player and teamplayer max values, move CommandPreProcessEvent to priority low to fix MobArena join related exploits -- v1.3.2.75 - properly save an ArenaGoal name to the round map (instead of its instance) -- v1.3.2.74 - fix a NPE in the EndRunnable when using rounds -- v1.3.2.73 - add a new command "regionclear" to manage region clearing exceptions -- v1.3.2.72 - add language and documentation for the WorldEdit addition -- v1.3.2.71 - add WorldEdit config to specify regions to autoload/autosave -- v1.3.2.70 - allow data values in MATERIAL definitions (only works with /pa set [node] hand) -- v1.3.2.69 - properly apply rewards when teamrewards is used -- v1.3.2.68 - remove repo pushing to maybe fix building for now -- v1.3.2.64 - fix issue #143 - thanks to Oruss7! -- v1.3.2.63 - add some message output when class changing fails -- v1.3.2.62 - prepare module class change hooking -- v1.3.2.61 - address github issue #114 - add LibsDisguises support -- v1.3.2.60 - fix CTF being messed up by people continuing to play -- v1.3.2.59 - fix update check -- v1.3.2.58 - /pa help - it still shows the colored standard reply even with sub-arguments -- v1.3.2.57 - address github issue #135 - language addition -- v1.3.2.56 - address github issue #141 - add config calcoffset to tweak block dissolve greediness -- v1.3.2.55 - fix Spectate Spectators being told they cannot teleport when switching view -- v1.3.2.54 - new Module: Spectate - uses the 1.8 SPECTATOR GameMode -- v1.3.2.51 - update to Java 7 -- v1.3.1.49 - fix an NPE on server shutdown -- v1.3.1.48 - update all the things in the doc -- v1.3.1.46 - pull #106 - thanks a TON to @Oruss7 for putting together this load of information! -- v1.3.1.45 - the final update for 1.7.9 - unless critical errors arrive. I need to get ready for 1.9 -- v1.3.1.44 - prevent an NPE in the WarmupJoin module -- v1.3.1.43 - revert the last commit and furthermore clarify and verify correctly. Modules build incoming -- v1.3.1.42 - fix a logic messups in an internal join check -- v1.3.1.41 - duel module finished -- v1.3.1.40 - allow to disable the Duel force ready & start -- v1.3.1.39 - duel module language finish -- v1.3.1.38 - finish off github issue #118 -- v1.3.1.37 - more shurtcut arena list fixes -- v1.3.1.36 - try to fix the round arena status check -- v1.3.1.35 - apply former fix for arena listing -- v1.3.1.34 - override only_shortcuts with allow_ungrouped to allow joining arenas not grouped under shortcuts -- v1.3.1.33 - properly format and save spawn offsets -- v1.3.1.32 - properly format and save spawn offsets -- v1.3.1.31 - properly allow for 5 arguments of /pa spawn -- v1.3.1.30 - fix github issues #115, #118 -- v1.3.1.29 - address github issue #112 -- v1.3.1.28 - how about we don't delete the spawn after offsetting it? -.- -- v1.3.1.26 - github issue #104 - EXPERIMENTAL! -- v1.3.1.25 - this time for real - we need to tell people they CAN decline :) -- v1.3.1.24 - add final language for github issue #97 -- v1.3.1.23 - add config for github issue #86 -- v1.3.1.22 - release build -- v1.3.1.21 - and more language nodes -- v1.3.1.20 - prepare Dual fixes and commit some language/message fixes -- v1.3.1.19 - fix another Exception in the time goal -- v1.3.1.18 - properly output unclaiming vs contesting flags in domination goal - language file consistency fixed -- v1.3.1.17 - fix some language derps and move the delayed class change to where it makes more sense -- v1.3.1.16 - fix github issue #108 - contesting (unclaiming) too late -- v1.3.1.15 - add github issue #100 - player.healforkill - true/false :) -- v1.3.1.14 - use the SNAPSHOT distinction and address github issue #85 -- v1.3.1.13 - hide the not-really stat type NULL (player name) -- v1.3.1.12 - fix github issue #95 by adding a null check -- v1.3.1.11 - clarify language for RespawnRelay and fix a little Exception in the Time goal -- v1.3.1.10 - address github issue #88 - properly keep players as DEAD when being relayed -- v1.3.1.9 - address github issue #87 - add THORNS damage handling -- v1.3.1.8 - properly deal with inventory protection -- v1.3.1.7 - how about we don't spam EVERYthing but spam after collecting everything, and inform people that we have prevented something? -- v1.3.1.6 - fix some mathematical and logical derps -- v1.3.1.5 - really add INVENTORY check - properly define new Infect commands [setprotect|getprotect] -- v1.3.1.4 - allow goals to deny BREAK, PLACE, TNT, TNTBREAK, DROP, INVENTORY, PICKUP, CRAFT - proof of concept! -- v1.3.1.1 - link to new jenkins. Thanks to @graywolf336 -- v1.3.0.558 - fix github issue #83 -- v1.3.0.557 - fix github issue #61 -- v1.3.0.556 - fix github issue #64 -- v1.3.0.555 - add x-offset and z-offset, so one can change the default behaviour of putting ppl on the middle of a block -- v1.3.0.554 - fix an NPE in some places due to a return value of null should be expected! -- v1.3.0.553 - add chat.toGlobal to allow private talking players to talk to the public with a prefix -- v1.3.0.552 - add CRAFT RegionProtection to prevent item crafting -- v1.3.0.551 - add damage.fromOutsiders (false) to allow players (and other entities) to hurt fighters -- v1.3.0.550 - properly check for some things before adding players to a class via command -- v1.3.0.549 - try to fix long usernames staying on signs -- v1.3.0.548 - prevent a NPE -- v1.3.0.547 - call the leave event - I am shocked noone noticed that until yesterday -- v1.3.0.546 - reverse all the things and do what I promised the last 2 commits -- v1.3.0.545 - fix books! (for real) -- v1.3.0.544 - fix books! -- v1.3.0.543 - trying again -- v1.3.0.542 - attempt to fix some data reading issues (for ink sacks and wool blocks) -- v1.3.0.541 - fix some display issues about max team players -- v1.3.0.540 - attempt to fix special character issues -- v1.3.0.539 - allow to take suicides into account for TDM -- v1.3.0.538 - still on github issue #78 - never remove perms! -- v1.3.0.537 - fix missing perms message, addressing github issue #78 -- v1.3.0.536 - finish github issue #78 - typo messup -- v1.3.0.535 - address github issue #78 - add language nodes for missing perms -- v1.3.0.534 - prevent tamed animals belonging to an arena player from teleporting -- v1.3.0.533 - finally fix github issue #76 - inventory reset messup -- v1.3.0.532 - address github issue #76 -- v1.3.0.531 - address github issue #64 -- v1.3.0.530 - add "classSwitchAfterRespawn", defaulting to false -- v1.3.0.529 - revert #523 - I don't care anymore - this HAS to fix it, otherwise I give up on development :P -- v1.3.0.528 - revert #519 - second attempt at fixing an issue on several implementations -- v1.3.0.527 - revert #518 - this fixed dbo issue #912 (duplications on Cauldron) but caused items disappearing on other implementations -- v1.3.0.526 - add more config settings for PlayerKillReward -- v1.3.0.525 - address DBO issue #923 -- v1.3.0.524 - address DBO issue #921 -- v1.3.0.522 - fix integer/integer divisions -.- -- v1.3.0.521 - clarify custom class determination debug -- v1.3.0.520 - clarify damage debug values -- v1.3.0.519 - forcefully place players where they joined if the player is disconnecting -- v1.3.0.518 - forcefully remove items when a player leaves the arena -- v1.3.0.517 - address DBO issue #907 - don't try to teleport null/dead players -- v1.3.0.516 - try fixing NOCAMP damage -- v1.3.0.515 - [IDEA] various fixes -- v1.3.0.511 - address DBO issue #888 - reset chat color if desired -- v1.3.0.510 - add mobs fighting by your side. Give classes a spawn egg with displayname "SPAWN" -- v1.3.0.509 - properly build #507 prefix -- v1.3.0.507 - add materialprefixes to the global config, for special Material names (bukkit:SAND) -- v1.3.0.506 - add '*' command for the whitelist to allow all commands -- v1.3.0.505 - add per command permissions - defaulting to old behaviour -- v1.3.0.504 - don't drop inventory if not desired -- v1.3.0.503 - fix the UUID interpretation; use player names for creation, not the UUID -.- -- v1.3.0.502 - how about we actually RUN the runnable? -- v1.3.0.501 - force /pa leave on final player death if no specate module present -- v1.3.0.500 - address ticket #869, #884, #792 - - add time.resetDelay (default: -1 --> off) - delay for resetting players (TP & inventory) - - support single SPAWN regions for team matches - - support lore and displayname for keepItems -- v1.3.0.499 - address ticket 792, 879, 881 - - attempt to fix the Food Goal to properly handle player deaths - - require explicit perms for /pa arenaclass (if desired) -- v1.3.0.498 - properly initiate late joining PlayerDeathMatch players -- v1.3.0.497 - check for explicit class perms, even though we have no Sign! -- v1.3.0.496 - minor fixes -- v1.3.0.495 - add Command Tab support; Big Command rewrite!! \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index c365da051..a904352e8 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -1,71 +1,78 @@ -*Note that `/pvparena` and `/pa` are the same. Furthermore, those commands only work as-is if you have only one arena, OR entered edit mode with an arena if you have more than one arena: -`/pa [arenaname] edit`* +# Command list -## Command list +Click on a command to get its syntax, usage examples and more information about its working. Commands `/pvparena` and + `/pa` are the same. -Click on a command to view more information about it. +> 🚩 **Note:** +> You always have to precise your arena name in commands (like `/pa myArena enable`) except for these cases: +> - For global admin commands +> - After you joined an arena +> - When you're editing an arena (see [`/pa edit`](commands/edit.md) command) +> - When you have only one arena -### Global Admin Commands -_(Permission: pvparena.admin)_ +
+ +## Global Admin Commands + +> ℹ Permission: pvparena.admin Command | Shorthand | Definition ------------- | ------------- | ------------- -[/pa debug](commands/debug.md) | /pa !d | Debugs nodes +[/pa debug](commands/debug.md) | /pa !d | Debug nodes +[/pa modules](commands/modules.md) | /pa !mi | Manage modules [/pa reload](commands/reload.md) | /pa !r | Reload arena configs -[/pa install](commands/install.md) | /pa !i | Installs a module -[/pa uninstall](commands/uninstall.md) | /pa !ui | Uninstalls a module -[/pa update](commands/update.md) | /pa !u | Updates a module -### Arena Administration Commands +## Arena Administration Commands -_(Permission: pvparena.admin OR ownership AND pvparena.create)_ +> ℹ Permission: pvparena.admin OR both ownership and pvparena.create Command | Shorthand | Definition ------------- | ------------- | ------------- -[/pa blacklist \(or whitelist\)](commands/blacklist.md) | /pa !bl (!wl) | Manage arena blacklists or whitelists -[/pa check](commands/check.md) | /pa !ch | Checks an arena configuration +[/pa blacklist](commands/blacklist.md) | /pa !bl | Manage arena blacklists +[/pa check](commands/check.md) | /pa !ch | Check an arena configuration [/pa class](commands/class.md) | /pa !cl | Manage arena classes [/pa classchest](commands/classchest.md) | /pa !cc | Manage arena class chests -[/pa create](commands/create.md) | /pa !c | Creates an arena -[/pa disable](commands/disable.md) | /pa !dis | Disables an arena. -/pa edit | /pa !e | Toggles editing of an arena -[/pa enable](commands/enable.md) | /pa !en | Enables an arena. -[/pa forcewin](commands/forcewin.md) | /pa !fw | Forces a player/team to win. +[/pa create](commands/create.md) | /pa !c | Create an arena +[/pa disable](commands/disable.md) | /pa !dis | Disable an arena. +[/pa edit](commands/edit.md) | /pa !e | Toggle editing of an arena +[/pa enable](commands/enable.md) | /pa !en | Enable an arena. +[/pa forcewin](commands/forcewin.md) | /pa !fw | Force a player/team to win. [/pa gamemode](commands/gamemode.md) | /pa !gm | Change the general gamemode of an arena [/pa goal](commands/goal.md) | /pa !g | Manage arena goals [/pa playerjoin](commands/playerjoin.md) | /pa !pj | Make a player join -[/pa protection](commands/protection.md) | /pa !p | Manages arena protections -[/pa region](commands/region.md) | /pa !rg | Manages arena regions -[/pa regionclear](commands/regionclear.md) | /pa !rc | Manages arena region clearing exceptions -[/pa regionflags](commands/regionflags.md) | /pa !rf | Manages arena flags -[/pa regiontype](commands/regiontype.md) | /pa !rt | Changes a region type -[/pa regions](commands/regions.md) | /pa !rs | Debugs regions | ^ +[/pa protection](commands/protection.md) | /pa !p | Manage arena protections +[/pa region](commands/region.md) | /pa !rg | Manage arena regions +[/pa regionclear](commands/regionclear.md) | /pa !rc | Manage arena region clearing exceptions +[/pa regionflags](commands/regionflags.md) | /pa !rf | Manage arena flags +[/pa regiontype](commands/regiontype.md) | /pa !rt | Change a region type +[/pa regions](commands/regions.md) | /pa !rs | Debug regions [/pa reload](commands/reload.md) | /pa !rl | Reload arena configs -[/pa remove](commands/remove.md) | /pa !rm | Removes an arena. -[/pa round](commands/round.md) | /pa !rd | Manages arena rounds +[/pa remove](commands/remove.md) | /pa !rm | Remove an arena. +[/pa round](commands/round.md) | /pa !rd | Manage arena rounds [/pa set](commands/set.md) | /pa !s | Set an arena config setting [/pa setowner](commands/setowner.md) | /pa !so | Sets the owner of an arena [/pa spawn](commands/spawn.md) | /pa !sp | Manage arena spawns [/pa start](commands/start.md) | /pa !go | Force starts an arena. [/pa stop](commands/stop.md) | /pa !st | Force stops an arena. -[/pa teams](commands/teams.md) | /pa !ts | Manages arena teams -[/pa teleport](commands/teleport.md) | /pa !tp | Teleports you to an arena spawnpoint -[/pa togglemod \[module\]](commands/togglemod.md) | /pa !tm | Activates/Deactivates module +[/pa teams](commands/teams.md) | /pa !ts | Manage arena teams +[/pa teleport](commands/teleport.md) | /pa !tp | Teleport you to an arena spawnpoint +[/pa togglemod](commands/togglemod.md) | /pa !tm | Enable or disable a module for an arena +[/pa whitelist](commands/whitelist.md) | /pa !wl | Manage arena whitelists -### Arena Standard Commands +## Arena Standard Commands -_(Permission: pvparena.user (defaults to true))_ +> ℹ Permission: pvparena.user (defaults to true) Command | Shorthand | Definition ------------- | ------------- | ------------- -/pa arenaclass | /pa -ac | Changes your class, if allowed (/pa -ac [classname]) -/pa list | none | List available arenas (red: disabled, yellow: edit, green: running) -/pa chat | /pa -c | Sets arena chat mode -/pa info | /pa -i | Displays the active modules of an arena and its settings -/pa join {team} | /pa -j | Joins an arena +[/pa arenaclass](commands/arenaclass.md) | /pa -ac | Change your class, if allowed +/pa chat | /pa -c | Set arena chat mode +/pa info | /pa -i | Display the active modules of an arena and its settings /pa help | /pa -h | Basic help. Splits into subsections. +[/pa join](commands/join.md) | /pa -j | Join an arena (specifying a team or not) /pa leave | /pa -l | Leave an arena -/pa ready | /pa -r | Readys you up or lists who is ready +/pa list | none | List available arenas (red: disabled, yellow: edit, green: running) +[/pa ready](commands/ready.md) | /pa -r | Ready you up or list who is ready /pa spectate | /pa -s | Spectate an arena -[/pa stats](commands/stats.md) | /pa -s | Shows [arena/global] statistics -/pa version | /pa -v | Shows detailed version information \ No newline at end of file +[/pa stats](commands/stats.md) | /pa -s | Show [arena/global] statistics +/pa version | /pa -v | Show detailed version information \ No newline at end of file diff --git a/doc/commands/arenaclass.md b/doc/commands/arenaclass.md new file mode 100644 index 000000000..0aa812c7b --- /dev/null +++ b/doc/commands/arenaclass.md @@ -0,0 +1,22 @@ +# Arenaclass command + +## Description + +This command allow players to change their class if it's allowed. It must be typed inside an arena. + +## Usage Examples + +Command | Definition +------------- | ------------- +/pa arenaclass [className] | switch you current arena class + +Example: `/pa -ac assassin` - get the assassin class + +## Details + +You can change you class in two cases : +- Before a match, when you're waiting in lounge +- During a match if `ingameClassSwitch` arena setting is enabled + +> 🚩**Tip:** +> With `classSwitchAfterRespawn` you can delay ingame class switching on next respawn \ No newline at end of file diff --git a/doc/commands/blacklist.md b/doc/commands/blacklist.md index c84697487..eac587772 100644 --- a/doc/commands/blacklist.md +++ b/doc/commands/blacklist.md @@ -2,18 +2,20 @@ ## Description -This command manages the block place / break blacklist for an arena. +This command manages the block place / break blacklist for an arena. With this, you are able to forbid +some actions to arena players. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf blacklist clear | clear the general blacklist -/pa ctf blacklist break clear | clear the BREAK blacklist -/pa ctf blacklist break add SNOW | add SNOW to the BREAK blacklist -/pa ctf blacklist place show | show the PLACE blacklist -/pa ctf blacklist break remove SNOW | remove SNOW from the BREAK blacklist +/pa [arena] blacklist clear | clear the general blacklist +/pa [arena] blacklist [break/place] clear | clear the BREAK or the PLACE blacklist +/pa [arena] blacklist [break/place] show | show a blacklist content +/pa [arena] blacklist [break/place] add [block] | add a block to a blacklist +/pa [arena] blacklist [break/place] remove [block] | remove a block from a blacklist -## Details +Example: `/pa ctf blacklist break add SNOW` - add SNOW block to the BREAK blacklist -Both ENUMs and ITEM IDs work, you can even add DATA values, e.g. WOOL:13 \ No newline at end of file +> **🚩 Tip:** +> [`/pa whitelist`](whitelist.md) command works exactly in the same way \ No newline at end of file diff --git a/doc/commands/check.md b/doc/commands/check.md index 5d8374202..e11db105f 100644 --- a/doc/commands/check.md +++ b/doc/commands/check.md @@ -8,8 +8,9 @@ The check command basically tries to parse an arena config, in case you are unsu Command | Definition ------------- | ------------- -/pa check myArena | debug the arena "myArena" -/pa check Teams | debug the arena "Teams" +/pa check [arena] | check the config of an arena + +Example: `/pa check myArena` - debug the arena "myArena" ## Hazards diff --git a/doc/commands/class.md b/doc/commands/class.md index 198300246..ed8fee47a 100644 --- a/doc/commands/class.md +++ b/doc/commands/class.md @@ -4,13 +4,18 @@ This command manages the arena classes. You can use it to show, edit and remove arena classes. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test class load Tank | Give you the class items of the Class "Tank" of the arena "test" -/pa temp class save Test | Save your inventory to the class items of the Class "Test" of the arena "temp" -/pa team class remove Blue | Remove the class "Blue" from the arena "team" +/pa [arena] class load [class] | Preview the class items of the class directly in your inventory +/pa [arena] class save [class] | Save your inventory to the class items of a class +/pa [arena] class remove [class] | Remove a class from an arena + +Example: use `/pa temp class save Test` to save your inventory to the class "Test" of the arena "temp" + +> **🚩 Tip:** +> Type `/pa leave` to leave class preview ## Hazards diff --git a/doc/commands/classchest.md b/doc/commands/classchest.md index 1548d2f55..c16a1e556 100644 --- a/doc/commands/classchest.md +++ b/doc/commands/classchest.md @@ -2,22 +2,12 @@ ## Description -This command manages the arena class chests. You use it to define a class item chest. +If you want, you can save class inventories inside chests instead of using [/pa class](class.md) command. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test classchest Ranger | Define the chest containing the items of the class "Ranger" from the arena "test" +/pa [arena] classchest [class] | Use a chest to store items of a class. You have to look at the chest. -## Hazards - -- - -## Details - -Look at a chest you want to set - -## ToDo - -- \ No newline at end of file +Example: `/pa test classchest Ranger` - Define the chest containing the items of the class "Ranger" from the arena "test". \ No newline at end of file diff --git a/doc/commands/create.md b/doc/commands/create.md index d7bff3c89..d0b2ceb89 100644 --- a/doc/commands/create.md +++ b/doc/commands/create.md @@ -4,22 +4,10 @@ The create command basically creates a standard, boring, arena. Given legacy types enhance this, but still you will probably want to customize your arena and definately continue setting it up by setting spawn points. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa create teamArena | create a standard Teams Arena -/pa create capture ctf | create a Capture The Flag Arena called "capture" +/pa create [arenaName] (free) | Create an arena. Arena uses team gamemode by default, add `free` parameter to use FFA gamemode instead. -## Details - -In order to have a quicker start when setting up an arena, you can use the oldschool legacy types, which will be supported until v2.0 I guess. Those types add pre-definitions to define how the arena works in general. You can still go ahead and adjust the goal setup to your needs! - -Valid legacy types include: - -- ctf -- free -- ctp -- sabotage -- tank -- spleef \ No newline at end of file +Example: `/pa create ffa free` - create a free for all arena named "ffa" \ No newline at end of file diff --git a/doc/commands/debug.md b/doc/commands/debug.md index b0b3458c4..cd0106de4 100644 --- a/doc/commands/debug.md +++ b/doc/commands/debug.md @@ -4,15 +4,16 @@ The debug command is used to spam the log file with a hell lot more of information, based on your current issue, or just in general when unsure where the issue comes from. -## Usage Examples +## Usage Command | Definition ------------- | ------------- /pa debug all | debug ALL classes -/pa debug 4 | debug class number 4 -/pa debug 4,7 | debug class 4 and 7 +/pa debug [value] | debug class or arena where name equals to `value` /pa debug none | disable debugging +Example: `/pa debug 4,7` - debug class 4 and 7 + ## Hazards The way PVP Arena debugs is known to **spam** a LOT. This rises exponentially the more people you have on. So if you want to debug and are unsure if you're debugging the right thing, diff --git a/doc/commands/disable.md b/doc/commands/disable.md index 8074a9853..e38a046b2 100644 --- a/doc/commands/disable.md +++ b/doc/commands/disable.md @@ -4,12 +4,13 @@ This command disables arenas, force stopping them in the first place. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test disable | disable the "test" arena -/pa temp disable | disable the "temp" arena +/pa [arena] disable | disable an arena + +Example: `/pa test disable` - disable the "test" arena ## Details diff --git a/doc/commands/edit.md b/doc/commands/edit.md new file mode 100644 index 000000000..cf656932e --- /dev/null +++ b/doc/commands/edit.md @@ -0,0 +1,14 @@ +# Edit command + +## Description + +The edit command switch your arena in edit mode. That temporarily closes your arena and allows you to type +any arena command without precising arena name. + +## Usage Examples + +Command | Definition +------------- | ------------- +/pa [arena] edit | toggle the edit mode of an arena + +Example: `/pa ctf edit` - enable or disable edit mode for "ctf" arena \ No newline at end of file diff --git a/doc/commands/enable.md b/doc/commands/enable.md index bcd700477..59b2ed1bd 100644 --- a/doc/commands/enable.md +++ b/doc/commands/enable.md @@ -4,10 +4,11 @@ This command re-enables an arena after disabling it. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test enable | enable the **"test"** arena -/pa temp enable | enable the **"temp"** arena +/pa [arena] enable | disable an arena + +Example: `/pa test enable` - enable the "test" arena diff --git a/doc/commands/forcewin.md b/doc/commands/forcewin.md index 9d92de2eb..ab0e57bee 100644 --- a/doc/commands/forcewin.md +++ b/doc/commands/forcewin.md @@ -4,10 +4,11 @@ This command forces a player/team to win. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test !fw slipcor | Make **slipcor** the winner in the **"test"** arena -/pa temp forcewin red | Make team **red** the winner in the **"temp"** arena +/pa [arena] forcewin [player/team] | Force a player or a team to win + +Example: `/pa temp forcewin red` - Make team **red** the winner in the **"temp"** arena diff --git a/doc/commands/gamemode.md b/doc/commands/gamemode.md index 7bc7e9bac..9602b6b1a 100644 --- a/doc/commands/gamemode.md +++ b/doc/commands/gamemode.md @@ -4,15 +4,12 @@ The gamemode defines the general play mode. Free For All or Team Play ? -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf gamemode ctf | set the gamemode of arena "ctf" to "team" -/pa free !gm free | set the gamemode of arena "free" to "free" +/pa [arena] gamemode [team/free] | Change gamemode of an arena -## Hazards - -Messing up here results in strange game logic interpretations, because several things are based on the decision if we have teams or not. +Example: `/pa ffa gamemode free` - set the gamemode of arena "ffa" to "free" ## Details diff --git a/doc/commands/goal.md b/doc/commands/goal.md index 919428e27..1721c9cdc 100644 --- a/doc/commands/goal.md +++ b/doc/commands/goal.md @@ -4,16 +4,20 @@ The goal command is used to activate certain goals, to enhance your arena or disable goals to narrow down the goals. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free goal Time | Enable the goal "Time" for the arena "free" -/pa ctf !g Time off | Disable the goal "Time" for the arena "ctf" +/pa [arena] goal [goal] (true/false) | Toggle a goal for an arena + +Example: `/pa free goal Time` - Enable the goal "Time" for the arena "free" ## Details You will receive a list of valid (installed) arena goals when trying to activate an unknown goal, so e.g. /pa [arenaname] !g list will show you possible goals. Giving no second argument will just toggle the goal status and show you the result, valid arguments to activate/deactivate include: -on | 1 | true || off | 0 | false \ No newline at end of file +on | 1 | true || off | 0 | false + +> 🚩 **Tip:** +> You can see active goals of your arena with command `/pa [arena] info` \ No newline at end of file diff --git a/doc/commands/install.md b/doc/commands/install.md deleted file mode 100644 index 86090bb44..000000000 --- a/doc/commands/install.md +++ /dev/null @@ -1,20 +0,0 @@ -# Install command - -## Description - -This command manages installation of modules. You can list available modules, see your current state, and install new modules. - -## Usage Examples - -Command | Definition -------------- | ------------- -/pa install | list all available modules -/pa install worldedit | install the worldedit module - -## Hazards - -Know your versions. If unsure, download the latest zip file from the files section, replace the files inside /files and then you can be sure you're up to date. Outdated modules lead to errors. - -## Details - -The list contains all available modules, with their respective version. Yellow names mark installed plugins, green version numbers mark as up to date, red version numbers show that you need to update the files. \ No newline at end of file diff --git a/doc/commands/join.md b/doc/commands/join.md new file mode 100644 index 000000000..74988e862 --- /dev/null +++ b/doc/commands/join.md @@ -0,0 +1,14 @@ +# Join command + +## Description + +Use this command to join an arena. You can specify a team. + + +## Usage Examples + +Command | Definition +------------- | ------------- +/pa [arena] join (team) | join a arena + +Example: `/pa ctf join blue` - join the blue team of "ctf" arena \ No newline at end of file diff --git a/doc/commands/modules.md b/doc/commands/modules.md new file mode 100644 index 000000000..b7cde8e37 --- /dev/null +++ b/doc/commands/modules.md @@ -0,0 +1,32 @@ +# Install command + +## Description + +This command manages modules. You can list installed modules, download latest version, install, uninstall, update and +upgrade your modules. + +## Usage + +Command | Definition +------------- | ------------- +/pa modules (list) | list all available modules (installed modules are highlighted) +/pa modules install [moduleName] | install a module (from the `files` folder) +/pa modules uninstall [moduleName] | uninstall a module (removing from `mods` folder) +/pa modules update | update all modules in `mods` folder with versions which are in `files` folder +/pa modules download | download latest release of modules pack and place it in `files` folder +/pa modules upgrade | upgrade all your modules (perform a download and an update) + + +## Directory management + +In order to increase performances, PVP Arena has two directories for mods: +- `/mods` contains only mods used in arenas and installed by admins +- `/files` contains all downloaded mods + +When you install a mod, the plugin copies it from `/files` to `/mods`. + + +## Details + +The result of list command contains all available modules, with their respective version. Yellow names mark installed +plugins, green version numbers mark as up to date, red version numbers show that you need to update the files. \ No newline at end of file diff --git a/doc/commands/playerjoin.md b/doc/commands/playerjoin.md index 544a05b5e..9fcd467ff 100644 --- a/doc/commands/playerjoin.md +++ b/doc/commands/playerjoin.md @@ -2,12 +2,13 @@ ## Description -This command force joins an online player into an arena. You can specify an arena team, or not. Just as the player would join the game. In fact it "makes the player call the join command" ;) +This command forces an online player to join an arena. You can specify an arena team, or not. Just as the player would join the game. In fact it "makes the player call the join command" ;) -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf playerjoin slipcor | make slipcor join the CTF arena, random team -/pa ctf !pj valera blue | make valera join the CTF arena, team blue +/pa [arena] playerjoin [player] (team) | force a player to join an arena + +Example: `/pa ctf !pj valera blue` - make valera join the CTF arena, team blue diff --git a/doc/commands/protection.md b/doc/commands/protection.md index 28f2c6391..64b8e406d 100644 --- a/doc/commands/protection.md +++ b/doc/commands/protection.md @@ -2,18 +2,20 @@ ## Description -Manage protections of a certain arena region +Manage protections of a certain [arena region](../regions.md). **When a protection is enabled, player actions +are prevented.** -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa main protection battlefield DROP | toggle the DROP protection of the arena "main"s region called "battlefield" -/pa hunger !p battlefield INVENTORY true | enable the INVENTORY protection of the arena "hunger"s region called "battlefield" +/pa [arena] protection [region] [protection] (true/false) | toggle a protection of an arena region + +Example: `/pa main protection battlefield DROP` - toggle the DROP protection of the arena "main"s region called "battlefield" ## Details -Erroneous protection flag usage will show you the supported flags, they include: (definition: when active) +Here is a quick list supported flags, they include: - BREAK - prevent player block breaking - FIRE - prevent fire spreading/burning @@ -29,4 +31,7 @@ Erroneous protection flag usage will show you the supported flags, they include: - PICKUP - prevent player item pickup - TELEPORT - prevent player teleportation -Always verify your protections with `/pa [arenaname] !rs [regionname]` \ No newline at end of file +
+ +> **🚩 Tip:** +> Check your protections with [`/pa [arenaname] !rs [regionname]`](regions.md) diff --git a/doc/commands/ready.md b/doc/commands/ready.md new file mode 100644 index 000000000..fe989dd00 --- /dev/null +++ b/doc/commands/ready.md @@ -0,0 +1,12 @@ +# Ready Command + +## Description + +This command passes players to "ready" state or lists ready players. It must be typed inside an arena. + +## Usage + +Command | Definition +------------- | ------------- +/pa ready | pass a player in "ready" state +/pa ready list | list ready players in current arena \ No newline at end of file diff --git a/doc/commands/region.md b/doc/commands/region.md index 3ad4f9e35..17fab65be 100644 --- a/doc/commands/region.md +++ b/doc/commands/region.md @@ -2,33 +2,33 @@ ## Description -Set up regions for an arena. Oh, and show their borders. ... and set some WIP values +Manage regions for an arena. More information is available [on dedicated page](../regions.md). -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free region | start setting up a region for the arena "free" -/pa free !r ball | save the cuboid region "ball" to the arena "free" -/pa ctf !r X spher | save the spheric region "X" to the arena "ctf" -/pa ctf !r remove X | remove the region "X" from the arena "ctf" -/pa free !r ball border | shows the border around the region "ball" of the arena "free" - +/pa [arena] region | start setting up a region for an arena (type again to leave region editor) +/pa [arena] region [regionName] (shape) | save a region for the arena. Cuboid is the default shape +/pa [arena] region [regionName] remove | remove an arena region +/pa [arena] region [regionName] border | show limits of a region + +Example: +- `/pa free !r ball` - save the cuboid region "ball" to the arena "free" +- `/pa ctf !r X remove` - remove the region "X" from the arena "ctf" ## Details +If we have to sum up, setting up an arena needs 3 things: + +- `/pa [arenaname] region` +- select two points that define the region +- `/pa [arenaname] region [regionshape]` -For a better display of HOW to setup regions, you might want to check out our tutorial section. -Setting up an arena needs 3 things: +Check out [our tutorial section](../regions.md) for more information. -`/pa [arenaname] region` -select two points that define the region -`/pa [arenaname] region [regionshape]` +
Valid regionshapes include: - CUBOID (default) - SPHERIC -- CYLINDRIC - -## ToDo - -Add more region shapes :D \ No newline at end of file +- CYLINDRIC \ No newline at end of file diff --git a/doc/commands/regionclear.md b/doc/commands/regionclear.md index b003f99ab..d1afde40b 100644 --- a/doc/commands/regionclear.md +++ b/doc/commands/regionclear.md @@ -2,20 +2,24 @@ ## Description -This command manages the regions' clearing behaviour by adding/removing exceptions. +By default, at the end of a match, all entities are removed from [arena regions](../regions.md). If you want to keep some kind of entities +(like armor stands for instance), you can manage an exception list with this command. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf regionclear VILLAGER | toggle the VILLAGER clearing of the arena "ctf" -/pa ctf !rc TNT true | enable the TNT clearing exception of the arena "ctf" (ALLOW TNT to stay after clearing!) +/pa [arena] regionclear [entity] (true/false) | toggle entity clearing of an arena -## Details -Valid entitytypes will be told when you mistype, or you can find them here: +Example: +- `/pa ctf regionclear VILLAGER` - toggle the VILLAGER clearing of the arena "ctf" +- `/pa ctf !rc TNT true` - add a clearing exception for TNT in the arena "ctf" (ALLOW TNT to stay after clearing!) + +## Details -https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html +Valid entitytypes will be told when you mistype, or you can find them +[on this page](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html). Giving no second argument will just toggle exception status and show you the result, valid arguments to activate/deactivate include: diff --git a/doc/commands/regionflags.md b/doc/commands/regionflags.md index 53020dcd0..0cebace49 100644 --- a/doc/commands/regionflags.md +++ b/doc/commands/regionflags.md @@ -2,14 +2,15 @@ ## Description -This command manages the regions' behaviour by enabling/disabling flags. +This command manages the [regions](../regions.md) behaviour by enabling/disabling flags. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf regionflag death1 DEATH | toggle the DEATH regionflag for the region "death1" of the arena "ctf" -/pa ctf !rf win2 WIN true | enable the WIN regionflag for the region "win2" of the arena "ctf" +/pa [arena] regionflag [region] [flag] (true/false) | toggle regionflag for an arena region + +Example: `/pa ctf !rf win2 WIN true` - enable the WIN regionflag for the region "win2" of the arena "ctf" ## Details @@ -17,8 +18,8 @@ There are several region flags that can be set: - NOCAMP - move in here, or get punished ! - DEATH - come in, die ! -- WIN - come in, WIN ! -- LOSE - come in, LOSE ! +- WIN - come in, win ! +- LOSE - come in, lose ! - NODAMAGE - players are invincible ! Giving no second argument will just toggle the flag status and show you the result, valid arguments to activate/deactivate include: diff --git a/doc/commands/regions.md b/doc/commands/regions.md index 150a8ae05..0f103173a 100644 --- a/doc/commands/regions.md +++ b/doc/commands/regions.md @@ -2,14 +2,16 @@ ## Description -This command displays a list of arena regions / their properties. +This command displays a list of arena [regions](../regions.md) / their properties. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free regions | list all arena regions of "free", and their shape and type -/pa free !rs ball | debug print properties of the region "ball" of the arena "free" +/pa [arena] regions | list all regions of an arena +/pa [arena] regions [region] | display properties of a given arena region + +Example: `/pa free !rs ball` - print properties of the region "ball" of the arena "free" ## Details diff --git a/doc/commands/regiontype.md b/doc/commands/regiontype.md index ca630b3ee..c87d812f0 100644 --- a/doc/commands/regiontype.md +++ b/doc/commands/regiontype.md @@ -2,47 +2,28 @@ ## Description -This command sets the region type which is essential for its functionality. +This command sets the [region](../regions.md) type which is essential for its functionality. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf regiontype exit EXIT | set the "ctf" region "exit" type to EXIT -/pa ctf !rt battlefield BATTLE | set the "ctf" region "battlefield" to BATTLE +/pa [arena] regiontype [region] [type] | change the type of an arena regions + +Example: `/pa ctf !rt battlefield BATTLE` - set the "ctf" region "battlefield" to BATTLE ## Details The region types include: -- CUSTOM => a default / module added region -- WATCH => the spectator region -- LOUNGE => the ready lounge region -- BATTLE => the battlefield region -- EXIT => the exit region -- JOIN => the join region -- SPAWN => the spawn region -- BL_INV => blacklist inventory access -- WL_INV => whitelist inventory access - -### BL_INV - -This region type blocks chest access for every team whichs name is in the region name, same for classes - -example names: - -`xxbluexx` => disallows the blue team -`RedSwordsman` => disallows the red team and any Swordsman - -### WL_INV - -This region type restricts chest access to teams / classes which names are part of the region name - -example names: - -`RedBlueRanger` => allows Red and Blue and Rangers to access chests -`%infected%` => allows the infected (class) to access chests - -## Todo - -add functionality like protection to the other region types +- CUSTOM +- WATCH +- LOUNGE +- BATTLE +- EXIT +- JOIN +- SPAWN +- BL_INV +- WL_INV + +Usage of each region type is detailed on [region documentation page](../regions.md#region-types). diff --git a/doc/commands/reload.md b/doc/commands/reload.md index bb926f514..702e4599a 100644 --- a/doc/commands/reload.md +++ b/doc/commands/reload.md @@ -5,13 +5,15 @@ The reload command does what you might think it does. It reloads the arena by force stopping it, removing it from the arena list, and loading it from the config definition. If you don't specify an arena and are not part of an arena, this command reloads all arenas. -## Usage Examples +## Usage Command | Definition ------------- | ------------- /pa reload | reload everything or the arena you're part of /pa reload ymls | reload main config, language and help ymls -/pa reload CTF | reload the arena called CTF +/pa [arena] reload | reload a specific arena + +Example: `/pa ctf reload` - reload the arena called CTF ## Details diff --git a/doc/commands/remove.md b/doc/commands/remove.md index 959e2cfac..7f087d7a4 100644 --- a/doc/commands/remove.md +++ b/doc/commands/remove.md @@ -4,17 +4,16 @@ This command does only one thing: Remove the arena. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test remove | remove the "test" arena -/pa temp remove | remove the "temp" arena +/pa [arena] remove | remove an arena -## Hazards -Well, once you did that, the file is gone. So when unsure, either make backups or use disable instead of remove. +Example: `/pa test remove` - remove the "test" arena -## Todo +## Hazards -Maybe some day I'll add a confirmation that tells you about the fact that the arena will be gone "for a long time" ;) +Well, once you did that, the associated file is deleted. So when unsure, either make backups or use +[disable](disable.md) command instead of remove. \ No newline at end of file diff --git a/doc/commands/round.md b/doc/commands/round.md index 3fddb978b..1a2e8bf89 100644 --- a/doc/commands/round.md +++ b/doc/commands/round.md @@ -1,20 +1,23 @@ # Round Command +> ⚠ This command has NOT been tested at ALL! Use at your own risks. + ## Description This command is a WIP to manage "round behaviour" in arenas. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free round | list rounds of arena "free" -/pa free round 1 | list goals of round 1 of arena "free" -/pa free round 1 Tank | Toggle the Tank goal for the first round of the arena "free" - -## Hazards - -This command has NOT been tested at ALL! This should be warning enough oO +/pa [arena] round | list rounds of an arena +/pa [arena] round [roundNumber] | list goals of an arena round +/pa [arena] round [roundNumber] [goal] | toggle a specific goal for a round of an arena + +Example: +- `/pa free round` - list rounds of arena "free" +- `/pa free round 1 ` - list goals of round 1 of arena "free" +- `/pa free round 1 Tank` - toggle the Tank goal for the first round of the arena "free" ## Details diff --git a/doc/commands/set.md b/doc/commands/set.md index 671795645..0da503543 100644 --- a/doc/commands/set.md +++ b/doc/commands/set.md @@ -2,30 +2,37 @@ ## Description -Sets a specific config node, or lists possible nodes. +Sets a specific config node of an arena configuration, or lists possible nodes. +It's an alternative to manually edit your config files. -## Usage Examples +> ⚠ If you mess up you might change the wrong node, erase parts of the config and render your config useless. +So only use this if you know what you're doing. + +## Usage Command | Definition ------------- | ------------- -/pa test set 0 | get the first page of the arena "test" -/pa test set minPlayers 5 | requires the "test" arena to have 5 players before starting - -## Hazards +/pa [arena] set [pageNumber] | show a list of editable config nodes of your arena +/pa [arena] set [configNode] [value] | edit the value of an arena config node -If you mess up you might change the wrong node, erase parts of the config and render your config useless. So only use this if you know what you're doing. +Examples : +- `/pa test set 0` - get the first page of editable nodes of the arena "test" configuration +- `/pa test set minPlayers 5` - require the "test" arena to have 5 players before starting ## Details -A number as only argument lists that page, a node and value tries to set the config node to the given value. - -You know know what the node types on the pages mean, but here they are: - -- boolean - true or false -- string - a word -- int - a whole number -- double - a decimal (e.g. 0.5) -- tp - a spawn point (exit, old, spectator) -- item - a bukkit ENUM or ID of a material -- items - e.g. class items, see the corresponding page about item definitions - +The value of a configuration node depends on its type. These types are show when you use `/pa [arena] set [pageNumber]`. +However, it's quite simple to guess a node type. +There are severals categories of types and here is how to set them : +- **boolean:** Quite simple, just type `true` or `false` +- **numbers:** They can be integer or floating-point numbers. Just type them after the name of your config node +- **string:** The easiest, just type the word you want. +- **material:** The name of a bukkit material. You can directly type material names picked from +[this list](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html) or type `hand` to get items you're +holding in your hand. +- **items:** A list of items is expected (for instance to give rewards). Type `inventory` to convert all your current +inventory to a list of items (metadata will be saved) or use `hand` get only get the item you're holding. + +> 🚩 **NB:** +> If you want to define items or material nodes directly in your config file, please check +>[this documentation](../items.md). \ No newline at end of file diff --git a/doc/commands/setowner.md b/doc/commands/setowner.md index 7f01ac749..117c1eaf2 100644 --- a/doc/commands/setowner.md +++ b/doc/commands/setowner.md @@ -2,12 +2,15 @@ ##Description -This command hands over ownership. This has to be either "%server%" or a player name. Note that the player name is NOT checked, but you can verify it with `/pa info` +This command hands over ownership. This has to be either "%server%" or a player name. Note that the player name is +NOT checked, but you can verify it with [`/pa info`](../commands.md#arena-standard-commands) ##Usage Examples Command | Definition ------------- | ------------- -/pa slip setowner slipcor | give slipcor ownership of the arena "slip" -/pa global setowner %server% | remove player ownership from the arena "global", set the server as owner +/pa [arena] setowner [player] | give player ownership of an arena + + +Example: `/pa global setowner %server%` - set the server as owner of the "global" arena diff --git a/doc/commands/spawn.md b/doc/commands/spawn.md index 9c9262d7b..1766a775d 100644 --- a/doc/commands/spawn.md +++ b/doc/commands/spawn.md @@ -4,22 +4,36 @@ Set an arena spawn to your current position, including orientation ! -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf spawn redspawn | sets the red team's spawn of the arena "ctf" -/pa free spawn spawnEAST | sets "spawnEAST" of the arena "free" +/pa [arena] spawn [spawnName] | Define a spawn for an arena + + +Example: +- `/pa ctf spawn redspawn` - sets the red team's spawn of the arena "ctf" +- `/pa free spawn spawnEAST` - sets "spawnEAST" of the arena "free" ## Details -If you get a message "spawn unknown", this is probably because you did not install / activate a goal / module ; be sure that you install and activate stuff you want to add, -e.g. the "Flags" goal, or the "StandardSpectate" module... +There are two syntax according to the [gamemode](gamemode.md) of your arena : +- If you're using a "free" arena, you can define unlimited spawns using syntax `/pa myArena spawn spawnX` where X should + be anything (word, digit, letter, etc). +- If your arena works with teams, you have to use `/pa myArena spawn teamspawn` where "team" is the name of one of your +team. + + +If you get a message "spawn unknown", this is probably because you did not install/activate a [goal](../goals.md) or +a [module](../modules.md). +Be sure you have installed and activated stuff you want to add, for instance the "Flags" goal, or the "StandardSpectate" +module... ## Spawn Offset -Since v1.3.1.31 you can define unique offsets for each spawn name, in order to not be placed on the block center but rather one edge: +You can define unique offsets for each spawn name, in order to not be placed on the block center but rather one edge: -- /pa {arenaname} spawn [spawnname] offset X Y Z +- `/pa [arena] spawn [spawnname] offset X Y Z` -For example 0.5 0 0.5 as X Y Z would work setting you on an edge. You might want to keep F3 at hand to see if you actually have to add or subtract to get to the right edge. \ No newline at end of file +For example 0.5 0 0.5 as X Y Z would work setting you on an edge. +You might want to keep F3 at hand to see if you actually have to add or subtract to get to the right edge. \ No newline at end of file diff --git a/doc/commands/start.md b/doc/commands/start.md index 323f5cbca..f471aa23e 100644 --- a/doc/commands/start.md +++ b/doc/commands/start.md @@ -4,13 +4,17 @@ This command force starts an arena for testing purposes or when players don't manage to get ready on their own. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test start | force start the arena called "test" +/pa [arena] start | force start an arena + +Example: +- `/pa test start` - force start the arena called "test" ## Hazards -If you start a game with only one player, the results may vary depending on the goals and the environment. You should know what you're doing ;) \ No newline at end of file +If you start a game with only one player, the results may vary depending on the goals and the environment. +You should know what you're doing ;) \ No newline at end of file diff --git a/doc/commands/stats.md b/doc/commands/stats.md index c6dd93c06..094669396 100644 --- a/doc/commands/stats.md +++ b/doc/commands/stats.md @@ -4,14 +4,19 @@ This command displays the top X players in a specific statistics type. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa stats LOSSES | shows the top 10 losers -/pa stats WINS 5 | shops the top 5 winners +/pa stats [statistic] (number) | show top 10 of a statistic for all the server. Change results size with "number" parameter. +/pa [arena] stats [statistic] (number) | show top 10 of a statistic for current arena game -Valid values are : +Examples: +- `/pa ctf stats DAMAGE` - shows the top 10 player damaged for the current CTF game +- `/pa stats WINS 5` - shops the top 5 winners for all the server + +## Details +Valid statistic values are : - WINS - LOSSES diff --git a/doc/commands/stop.md b/doc/commands/stop.md index 20886f829..81d4a1204 100644 --- a/doc/commands/stop.md +++ b/doc/commands/stop.md @@ -4,13 +4,12 @@ This command force stops an arena in case players are stuck / the game freezes and so on. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa test stop | force stop the arena called "test" +/pa [arena] stop | force stop an arena -## Hazards - -Should be clear, but... players will lose eventual game status that goals might offer. The arena game will start from scratch ;) \ No newline at end of file +Example: +- `/pa test stop` - force stop the arena called "test" \ No newline at end of file diff --git a/doc/commands/teams.md b/doc/commands/teams.md index 2df025e95..cc07e96fa 100644 --- a/doc/commands/teams.md +++ b/doc/commands/teams.md @@ -4,32 +4,38 @@ The teams command adds team management. Add, set and remove teams! -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa *(arena)* teams set blue GREEN | Set the blue team's color to green -/pa *(arena)* teams add yellow YELLOW | Add a yellow team -/pa *(arena)* teams remove blue | Remove the blue team -/pa *(arena)* teams | list all teams +/pa [arena] teams add [team] [color] | Add a new team to an arena +/pa [arena] teams set [team] [color] | Set color to existing team +/pa [arena] teams remove [team] | Remove a team +/pa [arena] teams | list all teams + +Examples: +- `/pa test teams set blue GREEN` - Set the blue team's color to green in the arena "test" +- `/pa ctf teams add yellow YELLOW` - Add a yellow team to the "ctf" arena ## Details You will need a proper color as a value. The possible colors are as follows: -- WHITE -- ORANGE -- MAGENTA -- LIGHT_BLUE -- YELLOW -- LIME -- PINK -- GRAY -- SILVER -- CYAN -- PURPLE -- BLUE -- GREEN -- RED -- BLACK +- AQUA +- BLACK +- BLUE +- DARK_AQUA +- DARK_BLUE +- DARK_GRAY +- DARK_GREEN +- DARK_PURPLE +- DARK_RED +- GOLD +- GRAY +- GREEN +- LIGHT_PURPLE +- RED +- WHITE +- YELLOW + diff --git a/doc/commands/teleport.md b/doc/commands/teleport.md index 5e0f024de..baf8f3f2e 100644 --- a/doc/commands/teleport.md +++ b/doc/commands/teleport.md @@ -2,19 +2,19 @@ ## Description -Teleports you to a specific spawn point of an arena. +Teleports you to a specific spawn point of an arena. This command should be for administration purpose and +not during game. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free teleport spawn2 | teleport to the spawn "spawn2" of arena "free" -/pa free teleport spawn | teleport to a random spawn of arena "free" -/pa ctf !tp bluespawn | teleport to the blue spawn of arena "ctf" +/pa [arena] teleport [spawnPoint] | teleport to a spawn point of an arena -## Hazards +Examples: +- `/pa free teleport spawn` - teleport to a random spawn of arena "free" +- `/pa ctf !tp bluelounge` - teleport to the blue lounge of arena "ctf" -You might not want to do that ingame unless you're godded ;) ## Details diff --git a/doc/commands/togglemod.md b/doc/commands/togglemod.md index a078af80b..006979744 100644 --- a/doc/commands/togglemod.md +++ b/doc/commands/togglemod.md @@ -4,18 +4,16 @@ Toggles a module on or off. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa free togglemod BattleGears | Toggles mod "BattleGears" in arena "free" -/pa ctf togglemod StandardSpectate | Toggles mod "Standard Spectate" in arena "ctf" -/pa ctf !tm WorldEdit | Toggles mod "WorldEdit" in arena "ctf" +/pa [arena] togglemod [module] | Toggles a mod for an arena -## Hazards - -You may need to restart your server for some mods to hook or take effect. +Example: +- `/pa ctf !tm WorldEdit` - Toggles mod "WorldEdit" in "ctf" arena ## Details -Toggling a mod allows you to simply change if a module is active or not. You can do further setting tweaks using the module-specific command or `/pa set` \ No newline at end of file +Toggling a mod allows you to simply change if a module is active or not. +You can do further setting tweaks using the module-specific command or [`/pa set`](set.md). \ No newline at end of file diff --git a/doc/commands/uninstall.md b/doc/commands/uninstall.md deleted file mode 100644 index 10c062734..000000000 --- a/doc/commands/uninstall.md +++ /dev/null @@ -1,17 +0,0 @@ -# Uninstall command - -## Description - -This command manages removal of modules. You can list available modules, see your current state, and remove installed modules. - -## Usage Examples - -Command | Definition -------------- | ------------- -/pa uninstall | list all available modules -/pa uninstall worldedit | uninstall the worldedit module - -## Details - -The list contains all available modules, with their respective version. Yellow names mark installed plugins, green version numbers mark as up to date, -red version numbers show that you need to update the files. \ No newline at end of file diff --git a/doc/commands/update.md b/doc/commands/update.md deleted file mode 100644 index 4b8758513..000000000 --- a/doc/commands/update.md +++ /dev/null @@ -1,20 +0,0 @@ -# Update command - -## Description - -This command manages updating of modules. You can list available modules, see your current state, and update modules. - -## Usage Examples - -Command | Definition -------------- | ------------- -/pa update | list all available modules -/pa update worldedit | update the worldedit module - -## Hazards - -Know your versions. If unsure, download the latest zip file from the files section, replace the files inside /files and then you can be sure you're up to date. Outdated modules lead to errors. - -## Details - -The list contains all available modules, with their respective version. Yellow names mark installed plugins, green version numbers mark as up to date, red version numbers show that you need to update the files. \ No newline at end of file diff --git a/doc/commands/whitelist.md b/doc/commands/whitelist.md index 695f54edf..4114f6a34 100644 --- a/doc/commands/whitelist.md +++ b/doc/commands/whitelist.md @@ -2,18 +2,20 @@ ## Description -This command manages the block place / break whitelist for an arena. +This command manages the block place / break whitelist for an arena. With this, you're able to restrict actions +in your arena. -## Usage Examples +## Usage Command | Definition ------------- | ------------- -/pa ctf whitelist clear | clear the general whitelist -/pa ctf whitelist break clear | clear the BREAK whitelist -/pa ctf whitelist break add SNOW | add SNOW to the BREAK whitelist -/pa ctf whitelist PLACE show | show the PLACE whitelist -/pa ctf whitelist break remove SNOW | remove SNOW from the BREAK whitelist +/pa [arena] whitelist clear | clear the general whitelist +/pa [arena] whitelist [break/place] clear | clear the BREAK or the PLACE whitelist +/pa [arena] whitelist [break/place] show | show a whitelist content +/pa [arena] whitelist [break/place] add [block] | add a block to a whitelist +/pa [arena] whitelist [break/place] remove [block] | remove a block from a whitelist -## Details +Example: `/pa ctf whitelist break add SNOW` - add SNOW block to the BREAK whitelist -Both ENUMs and ITEM IDs work, you can even add DATA values, e.g. WOOL:13 \ No newline at end of file +> **🚩 Tip:** +> [`/pa blacklist`](blacklist.md) command works exactly in the same way \ No newline at end of file diff --git a/doc/configuration.md b/doc/configuration.md index 5fde9778c..924ff6a3d 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -1,150 +1,204 @@ -# Configuration File +# Configuration file -This is a default configuation file. All parameters can be changed via in-game commands ([/pa set](commands/set.md)). +This page explains what are each parameter of arena config file. +All those parameters can be changed via in-game command ([/pa set](commands/set.md)). - configversion: 1.0.6.198 - chat: - colorNick: true - defaultTeam: false - enabled: true - onlyPrivate: false - toGlobal: none - cmds: - defaultjoin: true - whitelist: [] - damage: - armor: true - fromOutsiders: false - spawncamp: 1 - weapons: true - general: - classspawn: false - classSwitchAfterRespawn: false - customReturnsGear: false - enabled: true - gm: 0 - leavedeath: false - lang: none - owner: server - quickspawn: true - prefix: PVP Arena - showRemainingLives: true - smartspawn: false - time: -1 - type: none - wand: 280 - goal: # This part depends on gamemode and goals - livesPerPlayer: false - endCountDown: 5 - teamlives: - tlives: 10 +> ℹ This is a default configuration file. + +```yaml +configversion: 1.3.3.217 +chat: + colorNick: true #Use team color in chat + defaultTeam: false #Limit chat to team only + enabled: true #Allows chat usage + onlyPrivate: false #Limit chat to the arena + toGlobal: none #Begin word to talk to all the arena of onlyPrivate is active. E.g. @all +cmds: + defaultjoin: true #Join the arena if just typing /pa + #List of allowed commands in the arena + whitelist: + - ungod + - login +damage: + armor: true #Allow armor damage - false = unbreakable + bloodParticles: false #Show blood particles on fight + fromOutsiders: false #Allow external arena players to attack + spawncamp: 1 #If nocamp region flag is enabled, damage set to player + weapons: true #Allow weapon damage - false = unbreakable +general: + classspawn: false #Create specific class spawns. E.g. blueTankSpawn + classSwitchAfterRespawn: false #If IngameClassSwitch is enabled, switch class only on next respawn + customReturnsGear: false #If player has custom inventory, reload it after the match + enabled: true #Make arena accessible or not + gm: 0 #Arena game mode + leavedeath: false #Kill the player on battleground leaving + lang: none + owner: server #Set owner of the arena + regionclearexceptions: [] #List of regions where entities are not cleared + quickspawn: true #Spawn all players at the same time. If false, spawn player one by one. + prefix: MyArena #Name of the arena displayed in chat messages + showRemainingLives: true #Brodcast ramaning lives in chat + smartspawn: false #Spread players on spawn points in a balanced way + time: -1 #Arena day time in ticks, allow to make night arenas + type: free #Arena type : free or team + wand: STICK #Wand item for region selection +goal: + #Goal specific configurations, see 'Enhancement' part of documentation + livesPerPlayer: false + endCountDown: 5 + playerlives: + plives: 3 + teamlives: + tlives: 10 +items: + keepAllOnRespawn: false #Keep inventory on respawn + excludeFromDrops: none #List of items not dropped on kill + keepOnRespawn: none #List of items kept on respawn (if keepAllOnRespawn is disabled) + minplayers: 2 #Minimum number of players to start fighting + random: true + rewards: none #List of reward items given to win team team/player + takeOutOfGame: none #List of items kept from player inventory out the game +join: + range: 0 #Max distance from battleground to join arena. Set 0 to disable. + forceregionjoin: false #Limit arena join from "join" type region. + onlyifhasplayed: false #Allow player to join arena during game only if he played and left (with disconnection). Useful only if joinInBattle is enabled. +block: + blacklist: [] #Blacklist of blocks player can't interact + whitelist: [] #Whitelist of blocks player can interact +goals: + #List if enabled goals, see 'Enhancement' part of documentation +- PlayerLives +mods: + #List of enabled mods, see 'Enhancement' part of documentation +- BattlefieldJoin +- StandardLounge +- StandardSpectate +msg: + #Arena specific messages you can configure + lounge: Welcome to the arena lounge! Hit a class sign and then the iron block to + flag yourself as ready! + playerjoined: '%1% joined the Arena!' + playerjoinedteam: '%1% joined team %2%!' + starting: Arena is starting! Type &e/pa %1% to join! + youjoined: You have joined the FreeForAll Arena! + youjoinedteam: You have joined team %1%! +perms: + alwaysJoinInBattle: false #Allow join during game in any case + explicitArenaNeeded: false #Player needs permission pvparena.join.arenaName to play arena + explicitClassNeeded: false #Player needs permission pvparena.class.className to get a class + fly: false #Enable/Disable fly for players + loungeinteract: false #If true, players can interact with other players and blocks within lounge + joinInBattle: false #Allow join during a game + joinWithScoreboard: true #Allow to join arena with scoreboard with AutoVote Mod + teamkill: true #Allow players to kill players of their own team + specTalk: true #Allow spectators to use chat + spectatorinteract: false #Allow spectator to interact with others +player: + autoIgniteTNT: false #Ignite TNT on place + clearInventory: NONE #Clear player inventory on join. Set a specific game mode or ALL for any kind. + collision: true #Allow player collision with ENTITIES (players, arrows, tridents, armor stands, etc) + dropsEXP: false #Killed players drop XP + dropsInventory: false #Killed players drop their inventory + exhaustion: 0.0 #Set player exhaustion + hungerforkill: 0 #Not used + foodLevel: 20 #Initial food level + health: -1 #Set initial player health. Use -1 for default server value. Must be lower or equal than maxHealth. + healforkill: false #Heal player who kills another one + hunger: true #Enable hunger, if false feed level never decreases + itemsonkill: none #List of items given to player who kills another one + mayChangeArmor: true #Allow players to edit their armor slots in game + maxhealth: -1 #Set maximum health for player. 1 heart = 2 pts. Use -1 for default server value. + preventDeath: true #Not really kill player in order to avoid "you are died" message + refillCustomInventory: true #Refill custom player inventory after death + refillInventory: true #Players keeps inventory they had before their death + refillforkill: false #Reset class inventory of a player who killed another one + removearrows: false #Remove arrows on body after death + saturation: 20 #Set hunger saturation + quickloot: false #Automatically transfer chest content to inventory +protection: + enabled: true #Enable protections on regions. See "regions" part of documentation for more informations + punish: false #Damage players who don't respect protections + spawn: 0 #Radius around spawns where player fight is disallowed +ready: + autoClass: none #Name of class set automatically when player joins an arena. Set "none" to disable. Set to "custom" if you use "playerClasses". + block: IRON_BLOCK #Block player can hit to be ready. Has the same effect than typing /pa ready. + checkEachPlayer: false #Check if each player is ready before start + checkEachTeam: true #Check if each team is ready before start + enforceCountdown: false #If everyone is ready, game start before the end of countdown + minPlayers: 2 #Minimum number of players to play the arena + maxPlayers: 4 #Maximum number of players to play the arena + maxTeam: 0 #Maximim number of player in each team + neededRatio: 0.5 #Ratio of ready player needed to start countdown +time: + startCountDown: 10 #Start countdown in seconds + regionTimer: 10 #Time in ticks for region tasks. Don't change this. + teleportProtect: 3 #Number of seconds of invulnerability after teleport + resetDelay: -1 #Wait time (in ticks) to reset players when they exit arena + warmupCountDown: 0 #Warmup time (in seconds) + pvp: 0 #Time before PVP is enabled (in seconds) +tp: + #Spawnpoints where players go after specific event. Use "old" to use player location before arena. + death: old #Spawnpoint where player goes after death (only if he can't respawn after death) + exit: exit #Spawnpoint where player goes after he leaves the arena + lose: exit #Spawnpoint where player or team goes if they lose the match + win: exit #Spawnpoint where player or team goes if they win the match + offsets: [] #Spawnpoint offsets. List of strings with following format : "spawnName:xOffset;yOffset;zOffset" +uses: + classSignsDisplay: false #Display player names on class signs + deathMessages: true #Show death messages (from language file) + deathMessagesCustom: true #Not used + evenTeams: false #If true, requires the same number of players in each team + ingameClassSwitch: false #Allow to switch player class during a game + invisibilityfix: false #Force player to be visible + evilinvisibilityfix: false #Use this param if the previous one doesn't work + overlapCheck: true #Set to not check if the arena region collides with a running arena + playerclasses: false #Use players own inventory + scoreboard: true #Enable scoreboard + scoreboardrounddisplay: false #Show rounds number in scoreboard + suicidepunish: false #Increase other players score where someone commit suicide + teamrewards: false #Give reward to winning team + teleportonkill: false #Respawn KILLER after a kill + woolHead: false #Use a colored wool head as helmet +flagColors: + #Flag colors with format team: DYE_COLOR + #Use color among ORANGE, MAGENTA, LIGHT_BLUE, LIME, PINK, GRAY, LIGHT_GRAY, PURPLE, BLUE, GREEN, RED, CYAN, YELLOW, BLACK, WHITE + red: WHITE + blue: BLACK +classitems: + #Class items. See "items" part of documentation for more information + warrior: items: - excludeFromDrops: none - keepOnRespawn: none - minplayers: 2 - random: true - rewards: none - takeOutOfGame: none - join: - range: 0 - forceregionjoin: false - onlyifhasplayed: false - block: - blacklist: [] - whitelist: [] - goals: - - TeamLives - mods: - - BattlefieldJoin - - StandardSpectate - - StandardLounge - msg: - lounge: Welcome to the arena lounge! Hit a class sign and then the iron block to flag yourself as ready! - playerjoined: '%1% joined the Arena!' - playerjoinedteam: '%1% joined team %2%!' - starting: Arena is starting! Type &e/pa %1% to join! - youjoined: You have joined the FreeForAll Arena! - youjoinedteam: You have joined team %1%! - perms: - alwaysJoinInBattle: false - explicitArenaNeeded: false - explicitClassNeeded: false - fly: false - loungeinteract: false - joinInBattle: false - joinWithScoreboard: true - teamkill: true - specTalk: true - player: - autoIgniteTNT: false - clearInventory: NONE - dropsEXP: false - dropsInventory: false - exhaustion: 0.0 - hungerforkill: 0 - foodLevel: 20 - health: -1 - healforkill: false - hunger: true - mayChangeArmor: true - maxhealth: -1 - preventDeath: true - refillInventory: true - saturation: 20 - quickloot: false - protection: - enabled: true - punish: false - spawn: 0 - ready: - autoClass: Pyro # default class when player enter to the lobby - block: 42 # default : iron block - checkEachPlayer: false - checkEachTeam: true - enforceCountdown: false - minPlayers: 2 - maxPlayers: 0 - maxTeam: 0 - neededRatio: 0.5 - time: - startCountDown: 10 - regionTimer: 10 - teleportProtect: 3 - resetDelay: -1 - warmupCountDown: 0 - pvp: 0 - tp: # teleport location when ... (old is last player's location) - death: old - exit: old - lose: old - win: old - uses: - classSignsDisplay: false - deathMessages: true - evenTeams: false - ingameClassSwitch: false # players can change class via "/pa arenaclass Pyro" for example - invisibilityfix: false - evilinvisibilityfix: false - playerclasses: false - overlapCheck: true - teamrewards: false - woolHead: false - flagColors: - red: WHITE - blue: BLACK - classitems: - Ranger: 261,262:64,298,299,300,301 - Swordsman: 276,306,307,308,309 - Tank: 272,310,311,312,313 - Pyro: 259,46:3,298,299,300,301 - teams: - red: RED - blue: BLUE - spawns: # do not modify directly, use "/pa spawn" commands - bluespawn: labo,24,4,-13,-266.99993896484375,10.64997673034668 - redspawn: labo,17,4,-13,-89.84992218017578,10.500003814697266 - redlounge: labo,15,4,-13,272.699951171875,0.7499973177909851 - bluelounge: labo,26,4,-13,90.74996185302734,4.049993515014648 - spectator: labo,20,4,-7,180.2999725341797,26.549985885620117 - arenaregion: # do not modify directly, use "/pa region" commands - test: labo,16,1,-17,25,8,-9,cuboid,0,5054,BATTLE \ No newline at end of file + - type: IRON_SWORD + - type: SPLASH_POTION + meta: + potion-type: minecraft:regeneration + - type: SPLASH_POTION + meta: + potion-type: minecraft:weakness + - type: BOW + meta: + enchants: + ARROW_INFINITE: 1 + - type: ARROW + offhand: + - type: AIR + amount: 0 + armor: + - type: IRON_BOOTS + - type: IRON_LEGGINGS + - type: IRON_CHESTPLATE +teams: + #Team colors with format "team: DYE_COLOR" + #Use color among ORANGE, MAGENTA, LIGHT_BLUE, LIME, PINK, GRAY, LIGHT_GRAY, PURPLE, BLUE, GREEN, RED, CYAN, YELLOW, BLACK, WHITE + red: RED + blue: BLUE +spawns: + #List of registered spawn. See "Creation" part of documentation for more information + lounge: world,863,68,-997,0,0 + spectator: world,876,63,-997,90,0 + exit: world,321,67,221,0,5 + spawn1: world,873,58,-997,90,0 + spawn2: world,863,58,-1007,0,0 + spawn3: world,853,58,-997,-90,0 + spawn4: world,863,58,-987,180,0 +``` \ No newline at end of file diff --git a/doc/creation.md b/doc/creation.md deleted file mode 100644 index 8f502fb2e..000000000 --- a/doc/creation.md +++ /dev/null @@ -1,61 +0,0 @@ - -## Basic creation - -_\[Required] (Optional) Arena name is optional if you are inside an arena or in edit mode, but if you have more than one arena it is required._ - -### 1. Create the arena. - -`/pa create [Arena Name] (Legacy Type)` - -Valid types are: -- team -- teamdm -- dm -- free -- ctf -- ctp -- spleef -- tank -- sabotage - -### 2. Set spawns for the arena. - -/pa (Arena Name) spawn [spawntype] -Types are: [team]spawn / [team]lounge / spectator / spawn[x] (ffa only) - -By default you need: 2 spawns (red & blue) / 2 lounges (red & blue) / spectator zone. - -### 3. Create the battle region. - -`/pa (Arena Name) region` - -The default region setting tool is a stick. Set your region with left and right click. - -Then: - -`/pa (Arena Name) region [Region Name] (Region Shape)` - -Valid shape types: - -- cuboid -- spheric -- cylindric - -### 4. Place required items in the lounge - -Simply place the signs and on the first line put the class names. - -Default classes are: Swordsman / Tank / Pyro / Ranger - -Add more classes with the [class command](commands/class.md) - -Place the signs in each lobby, and an iron block (configurable). The iron block is the default ready block, and you push it when your ready to start the match. - -:triangular_flag_on_post: Tip : You can set a default class using the config parameter `autoClass`. - -### 5. Join the arena! - -`/pa [Arena Name] (join) (teamname)` - - -See the [video tutorial](https://www.youtube.com/watch?v=yyPJ6vlv09s) \ No newline at end of file diff --git a/doc/enhancements.md b/doc/enhancements.md deleted file mode 100644 index e9cd1092b..000000000 --- a/doc/enhancements.md +++ /dev/null @@ -1,99 +0,0 @@ -There are currently four ways of adding to the game: -# PVP Arena API - -The API features basic access to several things, based on very few requests. If you need something, give me a shout! -## PVP Arena Modules - -### Installation - -Unzip the module files (files tab, "PA Files v\*.\*.\*") into the /pvparena/files folder and install them via -`/pa install [modname]`, **activate per arena via** -`/pa [arenaname] !tm [modname]` - -### PVP Arena Goals - -Create ways to win the game or lose the game! - -Goal | Description -------------- | ------------- -[Beacons](goals/beacons.md) | Stand near beacons and claim them to win! -[BlockDestroy](goals/blockdestroy.md) | Destroy blocks (pre-installed) -[CheckPoints](goals/checkpoints.md) | Reach checkpoints in order to win (pre-installed) -[Domination](goals/domination.md) | Dominate flag positions (pre-installed) -[Flags](goals/flags.md) | Capture flags and bring 'em home (pre-installed) -[Food](goals/food.md) | Cook food and bring it home (pre-installed) -[Infect](goals/infect.md) | Infect people to win / kill infected players (pre-installed) -[Liberation](goals/liberation.md) | Jail dead players, possibility to unjail! (pre-installed) -[PhysicalFlags](goals/physicalflags.md) | Capture flags physically and bring 'em home (pre-installed) -[Pillars](goals/pillars.md) | Capture pillars by clicking/destroying! -[PlayerDeathMatch](goals/playerdeathmatch.md) | Player kills win (pre-installed) -[PlayerKillReward](goals/playerkillreward.md) | Player get better gears when killing (pre-installed) -[Rescue](goals/rescue.md) | Rescue a trapped Entity -[PlayerLives](goals/playerlives.md) | Player deaths lose (pre-installed) -[Sabotage](goals/sabotage.md) | Ignite TNT (pre-installed) -[Tank](goals/tank.md) | all vs one (pre-installed) -[TeamDeathConfirm](goals/teamdeathconfirm.md) | Confirmed Team kills win (pre-installed) -[TeamDeathMatch](goals/teamdeathmatch.md) | Team kills win (pre-installed) -[TeamLives](goals/teamlives.md) | Team deaths lose (pre-installed) -[Time](goals/time.md) | Time ends the arena (pre-installed) - -### PVP Arena Mods - -Hook into many different aspects of the game! - -Mod | Description -------------- | ------------- -[AfterMatch](mods/aftermatch.md) | could also be called "Sudden Death" -[Announcements](mods/announcements.md) | announce events happening -[ArenaBoards](mods/arenaboards.md) | stats display -[ArenaMaps](mods/arenamaps.md) | never lose yourself ever again! -[AutoSneak](mods/autosneak.md) | automatically hide player nametags by forcing sneak mode -[AutoVote](mods/autovote.md) | automatism -[BanKick](mods/bankick.md) | secure your arenas! -[BattlefieldGuard](mods/battlefieldguard.md) | secure your battlefield -[BattlefieldManager](mods/battlefieldmanager.md) | manage your battlefield -[BetterClasses](mods/betterclasses.md) | add potion effects and more to specific classes -[BetterGears](mods/bettergears.md) | give team colored leather -[BetterFight](mods/betterfight.md) | kill streaks and one-hit-kill items! -[BetterKillstreaks](mods/betterkillstreaks.md) | even more detailed kill streaks! -[BlockDissolve](mods/blockdissolve.md) | dissolve blocks under fighting players -[BlockRestore](mods/blockrestore.md) | restore the battlefield -[ChestFiller](mods/chestfiller.md) | fill battlefield chests with customizable content! -[Duel](mods/duel.md) | duel someone! -[EventActions](mods/eventactions.md) | do stuff when stuff happens -[Factions](mods/factions.md) | fix pvp not working -[FixInventoryLoss](mods/fixinventoryloss.md) | prevent loss by gamemode / inventory check -[FlySpectate](mods/flyspectate.md) | have players spectating a fight in fly mode -[Items](mods/items.md) | spawn (random) items -[LateLounge](mods/latelounge.md) | keep playing until enough ppl are joining -[MatchResultStats](mods/matchresultstats.md) | keep stats of player games, who won, who lost? -[PlayerFinder](mods/playerfinder.md) | allow players to find others with a compass -[Points](mods/points.md) | allow to restrict certain classes to require players to fight for better classes -[PowerUps](mods/powerups.md) | exactly that -[RealSpectate](mods/realspectate.md) | spectate the game, CounterStrike style! -[RedstoneTriggers](mods/redstonetriggers.md) | add win/lose triggered by redstone -[RespawnRelay](mods/respawnrelay.md) | add a relay for respawning players -[SinglePlayerSupport](mods/singleplayersupport.md) | Allow players to use an arena on their own! -[Skins](mods/skins.md) | add custom skins to teams/classes -[SpecialJoin](mods/specialjoin.md) | join via buttons, levers, etc -[Spectate](mods/spectate.md) | use the new 1.8 SPECTATOR mode to allow flying and POV spectating -[Squads](mods/squads.md) | add squads to the game, basically only showing players belonging together apart from teams and classes. -[StartFreeze](mods/startfreeze.md) | freeze players at start -[TeamSizeRestrict](mods/teamsizerestrict.md) | a small mod to restrict the size of specific teams -[Titles](mods/titles.md) | send messages to players as the "title" command would do -[TempPerms](mods/tempperms.md) | add temporary perms -[Turrets](mods/turrets.md) | add turrets where players fire projectiles -[Vault](mods/vault.md) | add economy -[Walls](mods/walls.md) | define wall regions to simulate "The Walls" -[WorldEdit](mods/worldedit.md) | backup/restore regions -[WorldGuard](mods/worldguard.md) | import region definitions from WorldGuard - -### PVP Arena Region Shapes - -Create region shapes to customize your arena! Default: COBOID! - -Shape| Description -------------- | ------------- -[CUBOID](shapes/cuboid.md) | a standard region that all should know -[CYLINDRIC](shapes/cylindric.md) | a standing can/barrel region -[SPHERIC](shapes/spheric.md) | a sphere/ball \ No newline at end of file diff --git a/doc/faq.md b/doc/faq.md new file mode 100644 index 000000000..1585f4211 --- /dev/null +++ b/doc/faq.md @@ -0,0 +1,75 @@ +# Frequently Asked Questions + +## How I can create a spleef arena? + +When you create a minigame with PVPArena, you have to ask yourself "How will work score calculation?". In spleef case, +when a player dies, he looses the match. + +So you should use the [playerLives](goals/playerlives.md) goal (enabled by default). Build you arena and configure it +following [this guide](getting-started.md). + +You can restore you battlefield (snow ground) using [BlockRestore](mods/blockrestore.md) or +[Worldedit](mods/worldedit.md) module. Please check [modules documentation](modules.md) to learn more. + +
+ +## Can my players use their own inventories? + +Yes it is possible, just pass `playerclasses` parameter to `true`. You can do this directly by editing your config file +or use the [`/pa [arena] set`](commands/set.md) command. + +Then you can propose player inventories as a class: corresponding class name is `custom`. If you want this class by +default, just set `autoclass` parameter to `custom`. + +Finally, if you want to return player inventory as it was before the beginning of the match, pass `customReturnsGear` to +true. + +
+ +## How can I use arena commands from a command block? + +Maybe you will wish to use buttons, pressure plates and command blocks to allowing players to choose their class, get +ready or leave the arena. + +Most of PvPArena commands must be types by players (in order to keep context). So if you want to use plugins commands in +a command block, you will have to use a **sudo** plugin. Utility plugins like +[EssentialsX](https://www.spigotmc.org/resources/essentialsx.9089/) already include this. + +"Sudo" make possible to type a command as if player typed it. For instance, if you a to create a command block to leave +an arena, use the command `sudo @p pa leave`. + +> âš™ **Technical precision:** +> Since Minecraft 1.13, spigot based servers does no longer support command selectors (like `@p`). If you want to use it +> you will have to use a plugin like [CommandHook](https://www.spigotmc.org/resources/commandhook.61415/). + +
+ +## How to regen my battlefield after a game? + +Currently, there are two ways to regen battlefield after a match. You can use either +[BlockRestore](mods/blockrestore.md) module or [WorldEdit](mods/worldedit.md) module. + +Here is a quick list of precisions to support your choice: +* BlockRestore: + * Reset only blocks broken by players + * Asynchronous + * Perfect for arena where few blocks are destroyed (like spleef) +* WorldEdit: + * Needs WorldEdit plugin (obviously) + * Regenerates everything + * Can regen large areas but is synchronous + +Check dedicated documentation pages to get more information. + +
+ +## Is there a way to automatically put a player into spectator mode on death instead of them having to leave the match and then rejoin as a spectator? + + +Just set `tp.death` to `spectator` in your arena config file (or with [`/pa [arena] set`](commands/set.md) command). + +
+ +## Still have questions? + +Don't hesitate to [get in touch](../readme.md#support) with us 😉 diff --git a/doc/getting-started.md b/doc/getting-started.md new file mode 100644 index 000000000..49c314fe3 --- /dev/null +++ b/doc/getting-started.md @@ -0,0 +1,126 @@ +# Getting Started + +
+ +> **🚩 Syntax tip:** +> [required] indicates a required parameter +> (optional) indicates an optional parameter +> + + +## Foreword: what's an arena? + +Before creating your first arena, you have to understand what's. +Arena is immaterial, it's a game configuration you create with goals, teams, classes, etc. It references your arena +config file created at `/plugins/pvparena/yourArenaName/config.yml`. So your arena defines how your game takes place. + +In this arena, only two things are bind to locations: spawn point and regions. So if you need to move your arena in +another place, don't destroy it, just redefine your spawn points and your regions. + +
+ +## 1. Create the arena + +Just type this command to create your arena: + +`/pa create [newArenaName] (free)` + +By default your arena will work with a team system. If you add the `free` option, your arena will work on a *Free for +all* (FFA) game mode. + +> **🚩 Tip:** +> This parameter can be changed using [/pa gamemode](commands/gamemode.md) command or in your config file by +> setting `general.type` parameter to `free` or `none`. + +
+ +## 2. Set goals for the arena + +By default, your arena will use [TeamLives](goals/teamlives.md) goal if your arena is in team mode and +[PlayerLives](goals/playerlives.md) goal otherwise. If you're ok with this, go to the next point, otherwise please +continue reading. + +You can choose a custom goal [in the list](goals.md) and set it for your arena with the command: +`/pa [arenaName] goal [goalName]` + +Each goal has its own setup, so take the time to read [documentation](goals.md) of the goal you want to use. + +You will find more information about this command [on this link](commands/goal.md). + +> **Reminder:** +> Don't forget to remove _TeamLives_ goal if you don't use it 😉 + +
+ +## 3. Set spawn points + +Now you have to create game spawn points by using this command: +`/pa [arenaName] spawn [spawnType]` + +##### Team arenas +For team arenas, spawn types are: `[team]spawn`, `[team]lounge`, `spectator`, `exit`. +So by default you need: 2 spawns (red & blue) / 2 lounges (red & blue) / 1 spectator zone / 1 exit. + +##### Free arenas +For **free** (FFA) arenas, spawn types are: `spawn[x]`, `lounge`, `spectator`, `exit`. +By default you need: 4 spawns (spawn1, spawn2, spawn3, spawn4) / 1 lounge / 1 spectator zone / 1 exit. + +
+ +> **🚩 Tips:** +>- In free arenas, you can create as many spawn points as you want. +>- You can use `/pa spawn` command again to move a spawn point + +
+ +## 4. Create the battle region + +> *This step is optional but really useful in mostly configurations* + +Now create the battle region with this command: + +`/pa [arenaName] region` + +It enables selection mode. Equip your hand with a **stick** and set your region with left and right click. + +Then type : + +`/pa [arenaName] region [yourNewRegionName]` + +Finally, specify your region type : + +`/pa [arenaName] regionType [regionName] BATTLE` + +> **🚩 Tips:** +> - By default your region is protected from block destruction and placing +> - Get a look to [the region documentation page](regions.md) to improve your arena regions + +
+ +## 5. Place required items in the lounge + +By default, four classes already exist : Swordsman, Tank, Pyro and Ranger. +You can chose to keep these classes or create new ones with the the [class command](commands/class.md). + +Then simply place signs near your **lounge** spawn point(s) and write the class names on the first line. + +Place the signs in each lobby, and an iron block (configurable). +The iron block is the default ready block that players can click on when they are ready. The match begins +when all players +are ready. + +> **🚩 Tips:** +> - Players can can choose their class with `/pa arenaclass [className]` command +> - You can set a default class using the config parameter `autoClass` +> - Players can also be ready typing `/pa ready`, that's why ready block is not mandatory + +
+ +## 6. Join the arena! + +Your first arena was created! Join the game with: + +`/pa [arenaName] (join) (teamName)` + +> **🚩 Tip:** +> If you just type `/pa [arenaName]` your team will be randomly selected. \ No newline at end of file diff --git a/doc/goals.md b/doc/goals.md new file mode 100644 index 000000000..568aff2fd --- /dev/null +++ b/doc/goals.md @@ -0,0 +1,25 @@ +## PVP Arena Goals + +Goals are ways to win the game or lose the game! You can see active goals of your arena with `/pa [arena] info`. + +To manage arena goals, use the [`/pa [arena] goal`](commands/goal.md) command. + +Goal | Description | Supported gamemodes +------------- | ------------- | ----------- +[BlockDestroy](goals/blockdestroy.md) | Destroy block of the other team | team +[CheckPoints](goals/checkpoints.md) | Reach checkpoints in order to win | free +[Domination](goals/domination.md) | Dominate flag/beacon positions | team +[Flags](goals/flags.md) | Capture flags and bring them at home | team +[Food](goals/food.md) | Cook food and bring it home | team +[Infect](goals/infect.md) | Infect people to win or kill infected players | free +[Liberation](goals/liberation.md) | Jail your enemies, free your allies! | team +[PhysicalFlags](goals/physicalflags.md) | Destroy enemy flag and place it at yours | team +[PlayerDeathMatch](goals/playerdeathmatch.md) | Score points by killing players | free & team +[PlayerKillReward](goals/playerkillreward.md) | Player get better gears when killing | free & team +[PlayerLives](goals/playerlives.md) | Last alive players win | free & team +[Sabotage](goals/sabotage.md) | Ignite TNT of the opposing team | team +[Tank](goals/tank.md) | all vs one | free +[TeamDeathConfirm](goals/teamdeathconfirm.md) | Confirmed Team kills win | team +[TeamDeathMatch](goals/teamdeathmatch.md) | Team kills win | team +[TeamLives](goals/teamlives.md) | Last alive team wins | team +[Time](goals/time.md) | Time ends the arena | free & team \ No newline at end of file diff --git a/doc/goals/beacons.md b/doc/goals/beacons.md index 459a3a941..b28a27637 100644 --- a/doc/goals/beacons.md +++ b/doc/goals/beacons.md @@ -15,7 +15,7 @@ A claimed beacon gives points every few seconds (tickinterval) that add up to a The GLASS blocks have to be added. In order to do that, use `/pa [arenaname] beacon`. This toggles edit mode. Don't forget to exit it again after setting the beacons. Set them by clicking the GLASS blocks which will color according to claim status. -## Config Settings +## Config settings - spamoffset => after how many updates should the arena announce? (default: 3) - claimrange => how near need players to be? (default: 3) diff --git a/doc/goals/blockdestroy.md b/doc/goals/blockdestroy.md index 730039194..41b9b61c4 100644 --- a/doc/goals/blockdestroy.md +++ b/doc/goals/blockdestroy.md @@ -1,22 +1,27 @@ # BlockDestroy - ## Description -This activates Blocks (to set), per team. Simply break the block of another team to remove a team life! +> ℹ This goal is designed for **team** gamemode -## Setup +## Description + +Each team have to destroy the block of opponent team(s). Blocks have lives, therefore when a block a no longer life, +its team is eliminated. -Blocks have to be added. In order to do that, use `/pa [arenaname] [teamname]block`. This enables setting. -Do this by clicking the block type (IRON_BLOCK by default) +## Setup -## Config Settings +Firstly, make sure the `blockType` parameter is set as you want. -- blockType \- the material checked for blocks (default: IRON_BLOCK) -- bdlives \- the maximum count of blocks/block destructions a team needs to win +If so, you can register destroyable blocks in your arena config. +In order to do that, use `/pa [arenaname] [teamname]block`. This will enable the selection mode. +Then left-click of the chosen block (that has to be of the defined block type). -## Supported Game Modes +## Config settings -Only supports team game mode! +- `blockType` - the material checked for blocks (default: IRON_BLOCK) +- `bdlives` - the maximum count of blocks/block destructions a team needs to win (default: 1) -## YouTube video +
-[click me](http://www.youtube.com/watch?v=ntloY1BTKHQ) +> 🚩 **Tip:** +> If you choose a colorable block (like RED_WOOL or WHITE_CONCRETE) all its variants will be supported. So you will be +> able, for instance, to set a red block for one team and a blue block for the other one. diff --git a/doc/goals/checkpoints.md b/doc/goals/checkpoints.md index ac3792bd3..4609b8b3f 100644 --- a/doc/goals/checkpoints.md +++ b/doc/goals/checkpoints.md @@ -1,28 +1,28 @@ # CheckPoints +> ℹ This goal is designed for **free** gamemode + ## Description -CheckPoints is designed for free for all game mode! +Players have to take a path composed by checkpoints. The first one every checkpoint up to the last (in order) wins! -It requires you to set spawns that players have to reach, and in case they get lost, they can get back to the latest checkpoint with /pa checkpoint. -First player to reach every checkpoint up to the last (in order) wins! +> 🚩 **One more thing:** +> Players can get back to the latest checkpoint with /pa checkpoint ## Setup Spawns have to be added. In order to do that, use `/pa [arenaname] checkpoint [number]`. This sets checkpoint number [number]. -Make sure you start with 0 and don't forget to add every single number, or else it will not be possible to win :P - -## Config Settings - -- cpclaimrange => how near need players to be? (default: 5) -- cplives => goal checkpoint index [0, 1, 2, ...] to reach -- cptickinterval => the amount of ticks to wait before checking for position (default: 20 = 1 second) +Make sure you start with 1 and don't forget to add every single number, or else it will not be possible to win 😋 -## Warnings +## Config settings -This game mode has to check for player's position. Based on the player and checkpoint count this can lag your server. But, how else should I determine a claimed checkpoint? :p +- `cpclaimrange` - how near need players to be? (default: 5) +- `cplives` - number of checkpoints to reach (default: 10) +- `cptickinterval` - the amount of ticks to wait before checking for position (default: 20 = 1 second) -## Supported Game Modes +
-Free for all - Teams might work but.... no idea +> ⚙ **Technical precision:** +> This goal has to check for player's position. Based on the player and checkpoint count this can lag your server. +> Unfortunately, there is no other way to determine a claimed checkpoint. diff --git a/doc/goals/domination.md b/doc/goals/domination.md index 4ec9a5176..5271554cb 100644 --- a/doc/goals/domination.md +++ b/doc/goals/domination.md @@ -1,36 +1,57 @@ # Domination +> ℹ This goal is designed for **team** gamemode + ## Description -Domination is designed to use teams. As always, it defaults to red and blue. +The game is simple : + +There are one or several flags that can be claimed by players. +When players are in the range of a flag, a load bar appears and they will claim the flag after few seconds. +Obviously, if a player on another team come also within the flag range, loading stops. -It activates Flags (to set) that can be claimed by players. In order to do that, they have to stand near that flag, -alone or at least only one team. Flags can be unclaimed if a different team or multiple teams are too close to a claimed flag. +When a flag is claimed, it take team color. Player of other team can get it back by the same process. +In this case, flag will be released in a first time (it takes white color) and only then it will take color of +second team. -Each claimed flag gives points every few seconds (tickinterval) that add up to a score, the first team to have enough points wins. +Each claimed flag gives points every few seconds (tickinterval) that add up to a score, the first team to have enough +points wins. ## Setup Flags have to be added.In order to do that, use `/pa [arenaname] flag`. This toggles edit mode. -Don't forget to exit it again after setting the flags. Set them by clicking the flag type (WOOL by default). - -## Config Settings +Don't forget to type command again in order to exit edit mode after setting the flags. +Set them by clicking the flag type (WOOL by default). + +Given that flag must be able to change color, you can use the following blocks as flagtype +(color prefix doesn't matter): +* WHITE_BANNER +* WHITE_CARPET +* WHITE_CONCRETE +* WHITE_CONCRETE_POWDER +* WHITE_GLAZED_TERRACOTTA +* WHITE_SHULKER_BOX +* WHITE_STAINED_GLASS +* WHITE_STAINED_GLASS_PANE +* WHITE_TERRACOTTA +* WHITE_WALL_BANNER + +I suggest you to try glass block with a beacon bottom the flag. When flag will be claimed, glass blocks will change its +color, altering beacon light ray in the same time :wink: + +## Config settings - spamoffset => after how many updates should the arena announce? (default: 3) - claimrange => how near need players to be? (default: 3) -- dlives => domination lives ( max points ) -- onlywhenmore => only score when more than half of the points are claimed -- tickinterval => the amount of ticks to wait before doing an update (default: 60 = 3 seconds) -- tickreward => the amount of points to give for each score (default: 1) - -## Warnings - -This game mode has to check for player's position. Based on the player count this can lag your server. But, how else should I determine a claimed flag? :p - -## Supported Game Modes +- dlives => domination lives (max points). (default: 10) +- onlywhenmore => only score when more than half of the points are claimed. (default: false) +- particlecircle => creates a circle of particles around each flag to mark capture radius. (default: true) +- tickinterval => the amount of ticks to wait before doing an update. (default: 60 = 3 seconds) +- tickreward => the amount of points to give for each score. (default: 1) -Supports both game modes, but we suggest you use the team game mode! +
-## YouTube video +> ⚙ **Technical precision:** +> This goal has to check for player's position. Based on the player and checkpoint count this can lag your server. +> Unfortunately, there is no other way to determine a claimed checkpoint. -[click me](http://www.youtube.com/watch?v=Xi7yNURxAjw) diff --git a/doc/goals/flags.md b/doc/goals/flags.md index 866e26bc9..2b2b0cb7d 100644 --- a/doc/goals/flags.md +++ b/doc/goals/flags.md @@ -1,29 +1,50 @@ # Flags +> ℹ This goal is designed for **team** gamemode + ## Description -This activates Flags (to set), per team. Team A captures the flag of team B and brings it home. To do this, simply hit the flag / your flag. +There is a flag per team. Team A captures the flag of team B and brings it home. +To do this, simply hit/click on flags. ## Setup -Flags have to be added.In order to do that, use `/pa [arenaname] [teamname]flag` \- this enables setting. - -Do this by clicking the flag type (WOOL by default). Don't click with your wand, just click with your hand or anything else. - -You can activate a special "touchdown" way of playing. Set a flag called "touchdown", it will be BLACK ingame. Players claim this flag and bring it home. Only one team can bring this flag home, obviously :) - -## Config Settings - -- flives \- the count of flags being brought home that lead to winning -- flagType \- the material checked for flags (default: WOOL) -- mustBeSafe \- do claimed flags prevent bringing home other flags? \- (default: true) -- woolFlagHead \- should PVP Arena enforce putting a wool head on flag carriers? - (default: true) -- effect \- the potion effect a player should get when carrying the flag (default: none; possible value: SLOWx2 - slowness, level 2 ; see bukkit docs - -## Supported Game Modes - -Only supports team game mode! - -## YouTube video - -[click me](http://www.youtube.com/watch?v=SuL78bce-f0) +Firstly, check if flag type is that you want (wool by default) or change it by editing +your arena configuration ou using `/pa set` command. +You can use any solid block as flag. Flags automatically take team color if flag type is one +of the following material (color prefix doesn't matter): + +* WHITE_BANNER +* WHITE_CARPET +* WHITE_CONCRETE +* WHITE_CONCRETE_POWDER +* WHITE_GLAZED_TERRACOTTA +* WHITE_SHULKER_BOX +* WHITE_STAINED_GLASS +* WHITE_STAINED_GLASS_PANE +* WHITE_TERRACOTTA +* WHITE_WALL_BANNER + +
+ +Flags have to be added afterwards. In order to do that, use `/pa [arenaname] [teamname]flag` \- this enables setting. +Just left click on your flag block. Clicked block must have same type as defined in your config. However nothing will +happen. + +> 🚩 **One more thing:** +You can activate a special "touchdown" way of playing. Set a flag called "touchdown", it will be BLACK ingame. +Players claim this flag and bring it home. Only one team can bring this flag home, obviously :) + +
+ +## Config settings + +- `flives` \- the count of flags being brought home that lead to winning +- `flagType` \- the material checked for flags (default: WHITE_WOOL). Plugin handle automatically flag colors if flagType +is a colorable item. +- `mustBeSafe` \- do claimed flags prevent bringing home other flags? \- (default: true) +- `woolFlagHead` \- should PVP Arena enforce putting a wool head on flag carriers? - (default: true) +- `effect` \- the potion effect a player should get when carrying the flag (default: none; possible value: SLOWx2 - +slowness, level 2) ; [see bukkit docs](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html) +- `alterOnCatch` \- change flag aspect when a player catch it. If flag is colorable (list below), color is passed to white + otherwise block is replaced by bedrock. (default: true) diff --git a/doc/goals/food.md b/doc/goals/food.md index a937bde90..844b49127 100644 --- a/doc/goals/food.md +++ b/doc/goals/food.md @@ -1,18 +1,22 @@ # Food +> ℹ This goal is designed for **team** gamemode + ## Description -Your players are hungry! The first team gathering enough cooked food items (of their type) wins the game. +Players are hungry! The first team gathering enough **cooked** food items (of their type) wins the game. The following food types exist: +- Beef +- Chicken +- Cod +- Mutton +- Porkchop +- Potato +- Salmon -- RAW_BEEF => COOKED_BEEF -- RAW_CHICKEN => COOKED_CHICKEN -- RAW_FISH => COOKED_FISH -- POTATO_ITEM => BAKED_POTATO -- PORK => GRILLED_PORK - -Note: the module does NOT include coal or furnaces, you have to manage that on your own :) +> 🚩 **Note:** +> The module does NOT include coal or furnaces, you have to manage that on your own ## Setup @@ -20,22 +24,17 @@ You have to prepare chests. To define those, use `/pa [arenaname] [teamname]food Finish the setting by clicking the chest that should be the team's chest. -This chest will be checked for incoming and outgoing food items (of the team type) You can optionally prepare furnaces so that a team can ONLY use this furnace. - -Set this by `/pa [arenaname] [teamname]foodfurnace` and hit the furnace. Teams not having a corresponding furnace will be able to access all of them. Note that one furnace can be set multiple times ! - -So red/blue can share a furnace and green/yellow :) Just set the same spot for multiple teams. - -## Config Settings - -- fmaxitems \- the item count that triggers win (default: 50) -- fplayeritems \- the item count players receive on start and respawn \- (default: 50) -- fteamitems \- the item count the team receives on start, divided by team members \- (default: 100) +This chest will be checked for incoming and outgoing food items (of the team type). You can optionally prepare furnaces so that a team can ONLY use this furnace. -## Supported Game Modes +Set this by `/pa [arenaname] [teamname]foodfurnace` and hit the furnace. -Only supports team game mode! +> 🚩 **Notes:** +> - Teams not having a corresponding furnace will be able to access all of them. +> - One furnace can be set multiple times! Just set the same spot for multiple teams. For example, +> red and blue teams can share the same furnace. -## YouTube video +## Config settings -[click me](http://www.youtube.com/watch?v=ntloY1BTKHQ) +- `fmaxitems` \- the item count that triggers win (default: 50) +- `fplayeritems` \- the item count players receive on start and respawn \- (default: 50) +- `fteamitems` \- the item count the team receives on start, divided by team members \- (default: 100) diff --git a/doc/goals/infect.md b/doc/goals/infect.md index 634c0514a..9f9faab2c 100644 --- a/doc/goals/infect.md +++ b/doc/goals/infect.md @@ -1,28 +1,23 @@ # Infect +> ℹ This goal is designed for **free** gamemode + ## Description -Quite simple. A random player is infected, he can have special gear and it's everyone against that player. +A random player is infected, he can have special gear and everyone is against that player. Killing an infected player kicks him out of the game, killing a non infected player infects him. Either the infected win by killing everyone else, or the other way round. ## Setup -At least one special "infected" spawn has to be set. You know how to do that, right? `/pa [arena] spawn infected*` - -The other spawns are set like the standard free for all goals, with spawns named like spawn1 through spawn10 or alike. - -You can set a class called "%infected%" in order to give infected players special gear - -## Config Settings - -- iilives \- infected player's lives (1) -- inlives \- normal player's lives (1) +At least one special "infected" spawn has to be set. Type the following command: +[`/pa [arena] spawn infected*`](../commands/spawn.md) -## Warnings +The other spawns are set like the standard free for all goals, with spawns named like _spawn1_ through _spawn10_ or alike. -\- +You can set a class called `%infected%` in order to give infected players special gear. -## Supported Game Modes +## Config settings -Only supports free game mode! +- `iilives` \- infected player's lives (default: 1) +- `inlives` \- normal player's lives (default: 1) diff --git a/doc/goals/liberation.md b/doc/goals/liberation.md index 81235331b..3d0f34668 100644 --- a/doc/goals/liberation.md +++ b/doc/goals/liberation.md @@ -1,22 +1,22 @@ # Liberation +> ℹ This goal is designed for **team** gamemode + ## Description A medium complex game mode. Dead players are teleported to the killer team's jail. -They can be unjailed, liberated, get one life back, so to speak :) +Other team member of jailed players can liberate them by clicking on a button, giving them one life back. ## Setup -You have to add spawns for the jails, set them like every other spawn (bluejail, redjail) and on top of that, -you have to set a button that will trigger the liberation of jailed players. - -It needs to be a stone block, and you set it with `/pa [arenaname] [teamname]button` \- Set it by clicking the button. - -## Config Settings - -- llives \- the lives players have before being put to prison +You have to add spawns for the jails, set them with command [`/pa [arena] spawn [team]jail`](../commands/spawn.md). +Then you have to set a button, at the outside of the jail, that will trigger the liberation of jailed players. To do +that: +- place a **stone button** where you want +- type `/pa [arenaname] [teamname]button` (to open selection mode) +- do a left-click on your button -## Supported Game Modes +## Config settings -Only supports team game mode! +- `llives` \- the lives players have before being put to prison (default: 3) diff --git a/doc/goals/physicalflags.md b/doc/goals/physicalflags.md index 9f817621d..962fb3657 100644 --- a/doc/goals/physicalflags.md +++ b/doc/goals/physicalflags.md @@ -1,23 +1,49 @@ -# PhysicalFlags - ## Description - -This activates Flags (to set), per team. Team A captures the flag of team B and brings it home. To do this, simply break the flag block and click your flag when holding the flag block! - ## Setup - -Flags have to be added.In order to do that, use `/pa [arenaname] [teamname]flag` - this enables setting. - -Do this by clicking the flag type (WOOL by default). Don't click with your wand, -just click with your hand or anything else. - -You can activate a special "touchdown" way of playing. Set a flag called "touchdown", it will be BLACK ingame. Players claim this flag and bring it home. - -Only one team can bring this flag home, obviously :) - ## Config Settings - -- flives - the count of flags being brought home that lead to winning -- flagType - the material checked for flags (default: WOOL) -- mustBeSafe - do claimed flags prevent bringing home other flags? - (default: true) - -## Supported Game Modes - -Only supports team game mode! +# PhysicalFlags + +> ℹ This goal is designed for **team** gamemode + +## Description + +There is a flag per team. Team A have to **break** team B flag and brings it at home. +Point is scored when team A place team B flag on its own flag. + +## Setup + +Firstly, check if flag type is that you want (wool by default) or change it by editing +your arena configuration ou using `/pa set` command. +You can use any solid block as flag. Flags automatically take team color if flag type is one +of the following material (color prefix doesn't matter): + +* WHITE_BANNER +* WHITE_CARPET +* WHITE_CONCRETE +* WHITE_CONCRETE_POWDER +* WHITE_GLAZED_TERRACOTTA +* WHITE_SHULKER_BOX +* WHITE_STAINED_GLASS +* WHITE_STAINED_GLASS_PANE +* WHITE_TERRACOTTA +* WHITE_WALL_BANNER + +
+ +Flags have to be added afterwards. In order to do that, use `/pa [arenaname] [teamname]flag` \- this enables setting. +Just left click on your flag block. Clicked block must have same type as defined in your config. However nothing will +happen. + +> 🚩 **One more thing:** +You can activate a special "touchdown" way of playing. Set a flag called "touchdown", it will be BLACK ingame. +Players claim this flag and bring it home. Only one team can bring this flag home, obviously :) + +
+ +## Config settings + +- `flives` \- the count of flags being brought home that lead to winning +- `flagType` \- the material checked for flags (default: WHITE_WOOL). Plugin handle automatically flag colors if flagType +is a colorable item. +- `mustBeSafe` \- do claimed flags prevent bringing home other flags? \- (default: true) +- `woolFlagHead` \- should PVP Arena enforce putting a wool head on flag carriers? - (default: true) +- `effect` \- the potion effect a player should get when carrying the flag (default: none; possible value: SLOWx2 - +slowness, level 2) ; [see bukkit docs](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html) + diff --git a/doc/goals/pillars.md b/doc/goals/pillars.md index 474fe89d3..0374b1554 100644 --- a/doc/goals/pillars.md +++ b/doc/goals/pillars.md @@ -1,52 +1,56 @@ -# Pillars - ## Description - -This activates pillars being defined by a wool block / pillar. People can then click/destroy them. Future versions will include actually physically bringing pillar blocks to your base to score - ## Setup - -You have to define pillars. Prepare a WOOL block, this will be the base of the pillar. This base will be the operational block and will react to: - -- clicking -- breaking -- placing against - -(based on your settings) - -In order to do that, use /pa [arenaname] [teamname]pillar* - this enables setting. Finally set the block by clicking the WOOL block. - -Note that there are three kinds of pillars: - -- empty pillar - - starts empty (duh ;) ) - - gains points for everyone, when claimed - - naming: Any name containing "pillar" and NOT containing a team name! -- team pillar (filled) - - starts with the predefined fill height, claimed by the team name - - gains no points for the initial claimed team - - naming: Any name starting with the team name and containing "pillar" -- team pillar (not filled) - - starts empty, only gives points to the team name contained, if claimed - - naming: Any name not starting with the team name, containing pillar, and containing the team name that should NOT get points - - ## Config Settings - -- announcetick (true) - should the score be publicly announced? -- breakable (true) - should you break the base to unclaim and place to claim? -- claimall (false) - should a team win by claiming all pillars? -- onlyfree (true) - only get points for free pillars (only the first type) - -- announceoffset (3) - how many ticks should pass before announcing the current scores? -- emptyheight (1) - how high should free pillars start? -- maxclicks (10) - how many clicks do people need to claim/unclaim? (overrides break allowing!! set to 0 for breaking ;) ) -- maxheight (5) - what is the full height of a pillar? -- pillives (10) - how many points does a team need to win? -- teamheight (2) - how high should a claimed pillar be at start? -- tickpoints (1) - points per pillar per tick (in the future you can disable this, but you shouldnt do this now ;) ) -- tickinterval (20) - the interval (in ticks, 20 per second!) to check for pillar points - -## Supported Game Modes - -Only supports team game mode! - ## YouTube video - -[click me](http://www.youtube.com/watch?v=Xi7yNURxAjw) +# Pillars + +## Description + +This activates pillars being defined by a wool block / pillar. People can then click/destroy them. Future versions will include actually physically bringing pillar blocks to your base to score + +## Setup + +You have to define pillars. Prepare a WOOL block, this will be the base of the pillar. This base will be the operational block and will react to: + +- clicking +- breaking +- placing against + +(based on your settings) + +In order to do that, use /pa [arenaname] [teamname]pillar* - this enables setting. Finally set the block by clicking the WOOL block. + +Note that there are three kinds of pillars: + +- empty pillar + - starts empty (duh ;) ) + - gains points for everyone, when claimed + - naming: Any name containing "pillar" and NOT containing a team name! +- team pillar (filled) + - starts with the predefined fill height, claimed by the team name + - gains no points for the initial claimed team + - naming: Any name starting with the team name and containing "pillar" +- team pillar (not filled) + - starts empty, only gives points to the team name contained, if claimed + - naming: Any name not starting with the team name, containing pillar, and containing the team name that should NOT get points + + +## Config settings + +- announcetick (true) - should the score be publicly announced? +- breakable (true) - should you break the base to unclaim and place to claim? +- claimall (false) - should a team win by claiming all pillars? +- onlyfree (true) - only get points for free pillars (only the first type) + +- announceoffset (3) - how many ticks should pass before announcing the current scores? +- emptyheight (1) - how high should free pillars start? +- maxclicks (10) - how many clicks do people need to claim/unclaim? (overrides break allowing!! set to 0 for breaking ;) ) +- maxheight (5) - what is the full height of a pillar? +- pillives (10) - how many points does a team need to win? +- teamheight (2) - how high should a claimed pillar be at start? +- tickpoints (1) - points per pillar per tick (in the future you can disable this, but you shouldnt do this now ;) ) +- tickinterval (20) - the interval (in ticks, 20 per second!) to check for pillar points + +## Supported Game Modes + +Only supports team game mode! + +## YouTube video + +[click me](http://www.youtube.com/watch?v=Xi7yNURxAjw) diff --git a/doc/goals/playerdeathmatch.md b/doc/goals/playerdeathmatch.md index 2b576632c..3a6abd23b 100644 --- a/doc/goals/playerdeathmatch.md +++ b/doc/goals/playerdeathmatch.md @@ -1,21 +1,15 @@ -# PlayerDeathMatch - ## Description - -This goal adds a counter to players killing others. The first one to have the required number of kills wins the game. - ## Setup - -\- - ## Config Settings - -- tdlives - how many kills does a team need to win? - -## Warnings - -\- - -## Supported Game Modes - -Supports team and free game mode! - ## YouTube video - -[click me](http://www.youtube.com/watch?v=KqBueDNbpD8) +# PlayerDeathMatch + +> ℹ This goal supports **team** and **free** gamemodes + +## Description + +This goal adds a counter to players killing others. The first one to have the required number of kills wins the game. + +## Setup + +There is no special setup. + +## Config settings + +- `tdlives` - how many kills does a team need to win? diff --git a/doc/goals/playerkillreward.md b/doc/goals/playerkillreward.md index 0c744a63d..e4ad5917f 100644 --- a/doc/goals/playerkillreward.md +++ b/doc/goals/playerkillreward.md @@ -1,27 +1,28 @@ -# PlayerKillReward - ## Description - -This activates configurable battle gear being given to players on kill, or on special kills - ## Setup - -There are 5 default kill gears, you can alter them or set new ones with `/pa [arenaname] !kr [kills]` \- of course this means, you have to equip yourself with the gear ppl should have, -and do that command. - -If you want to remove a kill stage, just add another word after the kill number. - -Default kills: - -- 5 \- Leather Armor & Wooden Sword -- 4 \- Chain Armor & Stone Sword -- 3 \- Gold Armor & Iron Sword -- 2 \- Iron Armor & Diamond Sword -- 1 \- Diamond Armor & Diamond Sword - -Note that the Kill number is to be understood as "kills left to win" - ## Config Settings - -\- - -## Supported Game Modes - -Supports team and free game mode! +# PlayerKillReward + +> ℹ This goal supports **team** and **free** gamemodes + +## Description + +In this goal, players have to make kills to wins. When they kill someone, their remaining kill number decreases and +they get a new item set. + +## Setup + +By default, there are 5 default kill gears: +- 5 \- Leather Armor & Wooden Sword +- 4 \- Chain Armor & Stone Sword +- 3 \- Gold Armor & Iron Sword +- 2 \- Iron Armor & Diamond Sword +- 1 \- Diamond Armor & Diamond Sword + +> Note that the Kill number is to be understood as "kills left to win" + +You can alter them or set new ones by doing that: +- Equip your own inventory with wanted gears (place armor and off-hand in good slots) +- Type `/pa [arenaname] !kr [remainingKillNumber]` + +## Config settings + +- `graduallyDown` - on death, keep current number of remaining kills instead of resetting it (default: false) +- `onlyGive` - just give new items to players instead of replacing their inventory (default: false) diff --git a/doc/goals/playerlives.md b/doc/goals/playerlives.md index cc173d6b3..89930d339 100644 --- a/doc/goals/playerlives.md +++ b/doc/goals/playerlives.md @@ -1,21 +1,19 @@ -# PlayerLives - ## Description - -The basic arena goal. Players have individual lives. After a player has run out of lives, he is removed. - ## Setup - -\- - ## Config Settings - -- plives \- the amount of lives a player has before being removed out of the arena - -## Warnings - -\- - -## Supported Game Modes - -Supports team and free game mode! - ## YouTube video - -[FreeForAll](http://www.youtube.com/watch?v=xBIxHoKMu98) +# PlayerLives + +> ℹ This goal supports **team** and **free** gamemodes + +## Description + +The basic arena goal. Players have individual lives. After a player has run out of lives, he is removed. + +> 🚩 **Note:** +> Contrary to [playerDeathMatch](playerdeathmatch.md) goal, here players can lose lives because of external elements +> (lava, falling, drowning, etc) + +## Setup + +There is no special setup. + +## Config settings + +- `plives` \- the amount of lives a player has before being removed out of the arena (default: 3) \ No newline at end of file diff --git a/doc/goals/rescue.md b/doc/goals/rescue.md index 75ad89a3d..0e48637f4 100644 --- a/doc/goals/rescue.md +++ b/doc/goals/rescue.md @@ -1,21 +1,24 @@ -# Rescue - ## Description - -A team game! Each team has a preset place where you hold captive an other team's entity. Invade the other team's base and "rescue" your entity! - ## Setup - -Set the entityspawn with `/pa [team]rescue` and clicking the block on which the entity will be spawned - ## Config Settings - -- rescue.flagType \- the entity Type, default: VILLAGER -- rlives \- the rescue count to achieve -- rescue.mustBeSafe \- can a team only bring home the entity if the own captive is not stolen? -- rescue.effect \- the potion effect for when carrying a rescued entity - -## Warnings - -\- - -## Supported Game Modes - -Only supports team game mode! +# Rescue + +## Description + +A team game! Each team has a preset place where you hold captive an other team's entity. Invade the other team's base and "rescue" your entity! + +## Setup + +Set the entityspawn with `/pa [team]rescue` and clicking the block on which the entity will be spawned + +## Config settings + +- rescue.flagType \- the entity Type, default: VILLAGER +- rlives \- the rescue count to achieve +- rescue.mustBeSafe \- can a team only bring home the entity if the own captive is not stolen? +- rescue.effect \- the potion effect for when carrying a rescued entity + +## Warnings + +\- + +## Supported Game Modes + +Only supports team game mode! diff --git a/doc/goals/sabotage.md b/doc/goals/sabotage.md index 9b791235d..440145ace 100644 --- a/doc/goals/sabotage.md +++ b/doc/goals/sabotage.md @@ -1,19 +1,15 @@ -# Sabotage - ## Description - -This activates TNT blocks (to set) that can be ignited by players that carry proper gear. An ignited TNT kills the team to whom the TNT belongs. - ## Setup - -TNTs have to be added.In order to do that, use `/pa [arenaname] [teamname]tnt` \- this enables tnt setting. Do it by clicking the TNT at the team's base. -Don't click with your wand, just click with your hand or anything else. - ## Config Settings - -\- - -## Warnings - -\- - -## Supported Game Modes - -Only supports team game mode! +# Sabotage + +> ℹ This goal is designed for **team** gamemode + +## Description + +Each team has a TNT block in its base. If this block is ignited by other players, the team is eliminated. + +## Setup + +TNTs have to be added. + +In order to do that, for each team: +- Type `/pa [arenaname] [teamname]tnt` - this enables tnt selector +- Left-click with your hand on the TNT block \ No newline at end of file diff --git a/doc/goals/tank.md b/doc/goals/tank.md index bb6b9313d..dbaaae043 100644 --- a/doc/goals/tank.md +++ b/doc/goals/tank.md @@ -1,20 +1,19 @@ -# Tank - ## Description - -This is a simple round. One random tank is assigned, he has special gear and it's everyone against that tank. Either the tank wins by killing everyone else, or the rest wins by killing the tank. - -You can optionally give a special gear to the tank, set the class "%tank%" - ## Setup - -A special "tank" spawn has to be set. You know how to do that, right? `/pa [arena] spawn tank` - ## Config Settings - -- tank.tlives \- the amount of lives players and the tank have before being removed - -## Warnings - -\- - -## Supported Game Modes - -Only supports free game mode! +# Tank + +> ℹ This goal is designed for **free** gamemode + +## Description + +One random tank is assigned, he has special gear and, everyone is against them. +Either the tank wins by killing everyone else, or the rest wins by killing the tank. + +## Setup + +A special "tank" spawn has to be set. Just type [`/pa [arena] spawn tank`](../commands/spawn.md). + +Optionally, you can give a special gear to the tank by [setting the class](../commands/class.md) `%tank%`. + +## Config settings + +- `tank.tlives` \- the amount of lives players and the tank have before being removed (default: 1) + diff --git a/doc/goals/teamdeathconfirm.md b/doc/goals/teamdeathconfirm.md index 8fe879d8b..2fc9b5662 100644 --- a/doc/goals/teamdeathconfirm.md +++ b/doc/goals/teamdeathconfirm.md @@ -1,23 +1,19 @@ # TeamDeathMatch +> ℹ This goal is designed for **team** gamemode + ## Description -Team play. Team kills are counted by collecting the drops when a player is killed, the first team collecting the set amount of drops wins. +Team kills are counted by collecting the drops when a player is killed, the first team collecting the set amount of drops wins. The big difference to standard PVP is that a team can prevent the other team from scoring by collecting the drops themselves. ## Setup -\- - -## Config Settings - -- tdcitem \- the amount of (enemy) drops a team has to collect in order to win - -## Warnings - -\- +There is no special setup. -## Supported Game Modes +## Config settings -Only supports team game mode! +- `tdcitem` \- item type dropped on player death (default: WHITE_WOOL) +- `tdclives` \- the amount of (enemy) drops a team has to collect in order to win, i.e. number of team lives +(default: 10) diff --git a/doc/goals/teamdeathmatch.md b/doc/goals/teamdeathmatch.md index 5e3372a76..c4adbdfc8 100644 --- a/doc/goals/teamdeathmatch.md +++ b/doc/goals/teamdeathmatch.md @@ -1,21 +1,16 @@ -# TeamDeathMatch - ## Description - -Simple team play. Team kills are counted, the first team killing that many people wins. - ## Setup - -\- - ## Config Settings - -- tdlives \- the amount of kills a team has to achieve in order to win - -## Warnings - -\- - -## Supported Game Modes - -Only supports team game mode! - ## YouTube video - -[click me](http://www.youtube.com/watch?v=rQ1ljlc6SJM) +# TeamDeathMatch + +> ℹ This goal is designed for **team** gamemode + +## Description + +Simple team play. Team kills are counted, the first team killing enough players wins. + +## Setup + +There is no special setup. + +## Config settings + +- `tdlives` - the amount of kills a team has to achieve in order to win (default: 10) +- `suicideScore` - does suicide is taken into account in score calculation? (default: false) diff --git a/doc/goals/teamlives.md b/doc/goals/teamlives.md index be979d884..1d12a2fc7 100644 --- a/doc/goals/teamlives.md +++ b/doc/goals/teamlives.md @@ -1,18 +1,13 @@ -# TeamLives - ## Description - -Very basic. Teams have lives. Once a team runs out of lives, it loses. - ## Setup - -\- - ## Config Settings - -- teamlives.tlives \- the amount of lives a team has before being removed - -## Warnings - -\- - -## Supported Game Modes - -Only supports team game mode! +# TeamLives + +## Description + +Very basic. Teams have lives. Once a team runs out of lives, it loses. + +## Setup + +There is no special setup. + +## Config settings + +- `teamlives.tlives` \- the amount of lives a team has before being removed diff --git a/doc/goals/time.md b/doc/goals/time.md index df76bb67a..bb6a0188d 100644 --- a/doc/goals/time.md +++ b/doc/goals/time.md @@ -1,23 +1,18 @@ -# Time - ## Description - -Guess what it does. \- Yes! it adds a timer, that ends the arena after a certain time. Based on all other active goals, it calculates the winning team/player. - -The scores that each goal gives are subject to change so ... don't rely on the output there :) - ## Setup - -\- - ## Config Settings - -- goal: - - time: - - timedend: 0 # the time in seconds the match should last - - winner: none # the team name that should win as soon as the time runs out - -## Warnings - -\- - -## Supported Game Modes - -Supports team and free game mode! +# Time + +> ℹ This goal supports **team** and **free** gamemodes. + +## Description + +This goal adds a timer, that ends the arena after a certain time. Based on all other active goals, it calculates the winning team/player. + +It is recommended to use this goal with another one. + +## Setup + +There is no special setup + +## Config settings + +- `timedend` - duration of the match in seconds (default: 0 - disabled) +- `winner` - the team name that should win as soon as the time runs out (default: none) diff --git a/doc/items.md b/doc/items.md index dd95164c2..6743dc126 100644 --- a/doc/items.md +++ b/doc/items.md @@ -1,38 +1,102 @@ - -Dealing with item strings is a pain, I know. But as there are so many different ways, amount, data value, enchantment, it was hard to implement that inside a short sentence ;) - -JavaDoc : [Bukkit Material ENUMs 1.8.8](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html) - -## Examples: - -**Swiftness Potion II** - -- items: 373~8226 - -**5x Colored wool** - -- items: 35~4:5 - -Minecraft Wiki : [Data Values => Potions](http://minecraft.gamepedia.com/Data_values#Potions) - - -*** - - -If you want to add enchantments, you will need to add a pipe as separator : `|` - -## Examples: - -**Diamond Sword with Sharpness LVL 3** - -- items: 276|16~3 - -**Iron Pick with Efficiency I** - -- items: 257|32~1 - -**Iron Pick with Efficiency I and Sharpness III** - -- items: 257|32~1|16~3 - -Minecraft Wiki : [Enchanting](http://minecraft.gamepedia.com/Enchantment#Enchantment_Types) +# Items in configuration files + +With PvPArena, all your arena configuration is stored in a [dedicated config file](configuration.md). For some reasons, +it could be useful to check it or edit it directly. This document will try to explain how you can edit list of items +for inventories or enhancements directly in arena config files. + +This is an **advanced level** tutorial, so if you aren't at ease with YAML config files, please use +[/pa class](commands/class.md) and [/pa set](commands/set.md) commands. + +JavaDoc : [Bukkit Material ENUMs](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html) + +## Create a simple item list: + +In order to create a basic list of items (without enchant or any enhancements), create a simple +YAML list with two keys : "type" and "amount". + +"Type" is the items name, it **must be** from the material enum page - *cf. above link* + +"amount" is the number of items you want to give. *This parameter is optional and, + if not set, equals to 1 (and 64 for arrows)* + +#### Example: + +```yaml +items: + - type: BOW + - type: ARROW + amount: 64 + - type: IRON_SWORD + - type: COOKED_BEEF + amount: 2 +``` + +## Create an advanced item list + +The principle is the same, you just have to add a **meta** key to list items and add the good +properties. + +### Enchantments + +You can add enchantments according the following instance. The enchantment names must be picked +from this page : [Bukkit enchantments](https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/enchantments/Enchantment.html) + +```yaml + myclassname: + items: + - type: IRON_SWORD + meta: + enchants: + DURABILITY: 3 + KNOCKBACK: 1 + offhand: + - type: SHIELD + armor: + - type: IRON_CHESTPLATE + meta: + enchants: + PROTECTION_ENVIRONMENTAL: 3 +``` + +### Custom names + +Add a *display-name* key with the name you want, it works with every item. + +```yaml + - type: COOKED_PORKCHOP + amount: 8 + meta: + display-name: Delicious bacon +``` + +### Potion effects + +You can use potion effects on these four items : +* POTION +* SPLASH_POTION +* LINGERING_POTION +* TIPPED_ARROW + +You can set a potion type like in the following example : + +```yaml + - type: TIPPED_ARROW + amount: 5 + meta: + potion-type: minecraft:slowness + - type: SPLASH_POTION + meta: + potion-type: minecraft:healing + - type: LINGERING_POTION + amount: 2 + meta: + potion-type: minecraft:strong_speed + - type: POTION + meta: + potion-type: minecraft:long_invisibilty +``` + +You can get potion effects on this page : [Potion type list](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionType.html) + +Be careful to prefix the effect with "minecraft:". You can give level 2 potions (like heath II) +prefixing the effect with **strong_** or long duration potions with the **long_** diff --git a/doc/languages.md b/doc/languages.md index ed6146298..7d691c83b 100644 --- a/doc/languages.md +++ b/doc/languages.md @@ -1,10 +1,18 @@ -These are the language files for PVP Arena, not (all) created or updated by me. +# Languages -Download the file and set lang: en to lang: value inside the config.yml +Here are the language files for PVP Arena, not (all) created or updated by me. -download | lang: value | language | author | date +Download the file and set `lang:` parameter inside the config.yml to +value of the second column. + +download | lang: value | language | author | last update ------------- | ------------- | ------------- | ------------- | ------------- -[link](http://www.slipcor.de/public/mc/pafiles/lang_en.yml) | 'en' (default) | English | slipcor | 2013/09/11 -[link](http://www.slipcor.de/public/mc/pafiles/lang_es-es.yml) | 'es-es' | Español | Anubis3467 | 2014/09/11 -[link](http://www.slipcor.de/public/mc/pafiles/lang_fr.yml) | 'fr' | Français | Fizzweapon | 2013/08/22 -[link](http://www.slipcor.de/public/mc/pafiles/lang_ru.yml) | 'ru' | Russki | llNeosGamer | 2013/04/13 \ No newline at end of file +[link](../lang/lang_en.yml) | 'en' (default) | English | slipcor/Eredrim | 2020 +[link](../lang/lang_es-es.yml) | 'es-es' | Español | Anubis3467 | 2014/09/11 +[link](../lang/lang_fr.yml) | 'fr' | Français | Eredrim | 2020 +[link](../lang/lang_ru.yml) | 'ru' | Russki | llNeosGamer | 2013/04/13 + +
+ +> 💡 **Did you know ?** +> You can propose your own language file by [creating an issue](https://github.com/Eredrim/pvparena/issues). \ No newline at end of file diff --git a/doc/mods/aftermatch.md b/doc/mods/aftermatch.md index 3e95f6acf..5447f0b6d 100644 --- a/doc/mods/aftermatch.md +++ b/doc/mods/aftermatch.md @@ -5,7 +5,7 @@ This mod adds a special ending to the game. After a set amount of time / kills, ## Installation Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/announcements.md b/doc/mods/announcements.md index 9c09a4d14..21c3c5967 100644 --- a/doc/mods/announcements.md +++ b/doc/mods/announcements.md @@ -5,7 +5,7 @@ Teach your arena how to talk! Every event can possibly trigger a global message ## Installation Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/arenaboards.md b/doc/mods/arenaboards.md index 9abf6bf48..cfd0575a4 100644 --- a/doc/mods/arenaboards.md +++ b/doc/mods/arenaboards.md @@ -5,7 +5,7 @@ This mod adds possibility to add arena boards to the game! ## Installation Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/arenamaps.md b/doc/mods/arenamaps.md index c4ecd99ae..ce427a421 100644 --- a/doc/mods/arenamaps.md +++ b/doc/mods/arenamaps.md @@ -8,7 +8,7 @@ This mod hands players a map of the arena. Optional display of lives and player/ Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/autosneak.md b/doc/mods/autosneak.md index 697b00800..d8c43ee68 100644 --- a/doc/mods/autosneak.md +++ b/doc/mods/autosneak.md @@ -7,7 +7,7 @@ This mod automatically sets players to sneak, in order for their nametags to be Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/autovote.md b/doc/mods/autovote.md index f95d5c21d..9fa701964 100644 --- a/doc/mods/autovote.md +++ b/doc/mods/autovote.md @@ -8,7 +8,7 @@ This mod adds an automated arena managing system. Once started, the end of an ar Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/bankick.md b/doc/mods/bankick.md index 837f5af4a..b0ed3787d 100644 --- a/doc/mods/bankick.md +++ b/doc/mods/bankick.md @@ -8,7 +8,7 @@ A fully functional kick/ban suite to get rid of derps that don't ready up or tro Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/battlefieldguard.md b/doc/mods/battlefieldguard.md index 48c382d52..f923079fe 100644 --- a/doc/mods/battlefieldguard.md +++ b/doc/mods/battlefieldguard.md @@ -7,7 +7,7 @@ This mod guards your battlefield. Entering people will be kicked/killed. Fun! Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/battlefieldmanager.md b/doc/mods/battlefieldmanager.md index 520e267ce..790e4f024 100644 --- a/doc/mods/battlefieldmanager.md +++ b/doc/mods/battlefieldmanager.md @@ -8,7 +8,7 @@ This mod allows to run one arena with several spawn setups. Save and load spawn Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/betterclasses.md b/doc/mods/betterclasses.md index f60338a61..3f76d80ef 100644 --- a/doc/mods/betterclasses.md +++ b/doc/mods/betterclasses.md @@ -8,7 +8,7 @@ This mod adds more to your classes, POTION effects and maximum player count! Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/betterfight.md b/doc/mods/betterfight.md index 531918aa9..19539bd7e 100644 --- a/doc/mods/betterfight.md +++ b/doc/mods/betterfight.md @@ -8,7 +8,7 @@ This mod enhances fighting, by adding one-hit-kill-items and kill streak announc Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/bettergears.md b/doc/mods/bettergears.md index baa54f699..3cd78f415 100644 --- a/doc/mods/bettergears.md +++ b/doc/mods/bettergears.md @@ -8,7 +8,7 @@ This mod adds colored armor to keep track of teams more easily. The class armor Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/betterkillstreaks.md b/doc/mods/betterkillstreaks.md index de513627f..0a54094bb 100644 --- a/doc/mods/betterkillstreaks.md +++ b/doc/mods/betterkillstreaks.md @@ -8,7 +8,7 @@ This mod enhances fighting, by adding kill streak potion effects or items Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/blockdissolve.md b/doc/mods/blockdissolve.md index 62b3ccd39..9dc6b608c 100644 --- a/doc/mods/blockdissolve.md +++ b/doc/mods/blockdissolve.md @@ -1,34 +1,20 @@ # BlockDissolve -## Description +## About -This mod adds another layer of tension. Blocks under the player will dissolve, great addition to spleef arenas! - -## Installation - -Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via - -- `/pa install [modname]`, activate per arena via -- `/pa [arenaname] !tm [modname]` - -## Setup - -\- +Blocks under the player will dissolve just few milliseconds after they walk on it. +Use it with [PlayerLives](../goals/playerlives.md) goal to create TNT Run arenas or +spice up your spleef games ! ## Config settings -- modules.blockdissolve.materials \- the material to dissolve data value / color is ignored -- modules.blockdissolve.startseconds \- the seconds to count down before the match starts +- modules.blockdissolve.materials \- the material to dissolve (default: SNOW and each kind of WOOL) +- modules.blockdissolve.startseconds \- the seconds to count down before the match starts (default: 10) - modules.blockdissolve.ticks \- the ticks after what time the block under the player should dissolve (20 ticks = 1 second) + (default: 40). -## Commands - -\- - -## Warnings - -\- - -## Dependencies +
-\- +> **🚩 Tips:** +>- BlockDissolve is compatible with [BlockRestore](./blockrestore.md), so you can use it to regen the floor after each game. +>- If you want to create a TNT Run arena, set ticks parameter to **8** diff --git a/doc/mods/blockrestore.md b/doc/mods/blockrestore.md index 12527e797..78a169677 100644 --- a/doc/mods/blockrestore.md +++ b/doc/mods/blockrestore.md @@ -1,23 +1,12 @@ # BlockRestore -## Description +## About -This mod activates BATTLE region restoring, after the match. - -## Installation - -Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via - -- `/pa install [modname]`, activate per arena via -- `/pa [arenaname] !tm [modname]` - -## Setup - -\- +This mod activates BATTLE [region](../regions.md) restoring after the match. ## Config settings -- hard \- should the mod restore EVERY block, regardless of a known chaged state? (default: false) +- hard \- the mod will restore EVERY block of your battle region, regardless of a known changed state (default: false) - offset \- the time in TICKS (1/20 second) that the scheduler waits for the next block to be replaced (default: 1) - restoreblocks \- restore blocks (default: true) - restorechests \- restore chest content (default: false) @@ -29,10 +18,18 @@ Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files f - `/pa [arena] !br clearinv` \- clear saved chest locations - `/pa [arena] !br offset X` \- set the restore offset in TICKS! -## Warnings +
+ +> **🚩 Tips:** +> - If you add new chests to your map, don't forget to register them with `/pa [arena] !br clearinv`. +> - BlockRestore is designed for simple block destruction and small areas. For other usages, please prefer +> [WorldEdit](./worldedit.md) mod. + +
+ +> âš™ **Technical precision:** +> Chest restoring lags badly for the first time, because it searches the BATTLE region(s) for chests and saves location +> of each of them. -Chest restoring lags badly for the first time, because it searches the BATTLE region(s) for chests, saves the locations and from then on it's simple. If you add more chests or remove some, you will want to run the clearinv command so chests are not forgotten or blocks are treated as chests -## Dependencies -\- diff --git a/doc/mods/chestfiller.md b/doc/mods/chestfiller.md index 5bc252aec..9116b4251 100644 --- a/doc/mods/chestfiller.md +++ b/doc/mods/chestfiller.md @@ -8,7 +8,7 @@ This mod adds random chest contents. It places stuff you can configure inside ch Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/duel.md b/doc/mods/duel.md index 6ed0bdbc7..63d74ba1e 100644 --- a/doc/mods/duel.md +++ b/doc/mods/duel.md @@ -8,7 +8,7 @@ This turns your arena into a 1:1 arena if possible, and if a player dares anothe Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/eventactions.md b/doc/mods/eventactions.md index b55c2e5ed..8e6e9e6c9 100644 --- a/doc/mods/eventactions.md +++ b/doc/mods/eventactions.md @@ -41,7 +41,7 @@ The following placeholders can be used to get dynamic output in your Commands/me Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/factions.md b/doc/mods/factions.md index de97549ae..419666907 100644 --- a/doc/mods/factions.md +++ b/doc/mods/factions.md @@ -8,7 +8,7 @@ This is a module that tries to override pvp fail due to other plugins cancelling Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/fixinventoryloss.md b/doc/mods/fixinventoryloss.md index b6a9eb4a4..85a351b31 100644 --- a/doc/mods/fixinventoryloss.md +++ b/doc/mods/fixinventoryloss.md @@ -8,7 +8,7 @@ Add methods to prevent ppl losing their stuff because other plugins mess around Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/flyspectate.md b/doc/mods/flyspectate.md index 067f9b1bf..1f4cd8637 100644 --- a/doc/mods/flyspectate.md +++ b/doc/mods/flyspectate.md @@ -8,7 +8,7 @@ Have players joining into an arena, to the spectator spawn. They are invisible a Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/items.md b/doc/mods/items.md index d11c3c719..88f6e0c9e 100644 --- a/doc/mods/items.md +++ b/doc/mods/items.md @@ -8,7 +8,7 @@ Add random items spawning at predefined spots! Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/latelounge.md b/doc/mods/latelounge.md index c8a07a6f5..ce083c574 100644 --- a/doc/mods/latelounge.md +++ b/doc/mods/latelounge.md @@ -8,7 +8,7 @@ Let people announce a join to an arena, yet keep playing until the minimum playe Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/matchresultstats.md b/doc/mods/matchresultstats.md index d357c49f6..4ecf8d8e5 100644 --- a/doc/mods/matchresultstats.md +++ b/doc/mods/matchresultstats.md @@ -10,7 +10,7 @@ A table will be created, but the database has to exist. Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/playerfinder.md b/doc/mods/playerfinder.md index c45e193b7..8c60075a7 100644 --- a/doc/mods/playerfinder.md +++ b/doc/mods/playerfinder.md @@ -10,7 +10,7 @@ Left click to point to the nearest player, right click to show the distance Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/points.md b/doc/mods/points.md index ff5baf1c1..d466c3ef5 100644 --- a/doc/mods/points.md +++ b/doc/mods/points.md @@ -8,7 +8,7 @@ This mod adds a little restriction to classes. Players have to choose lesser cla Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/powerups.md b/doc/mods/powerups.md index ce75412b5..88e8fb59b 100644 --- a/doc/mods/powerups.md +++ b/doc/mods/powerups.md @@ -8,14 +8,15 @@ This mod allows spawning of items that give special powers / bad things, fully c Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via -- `/pa [arenaname] !tm [modname]` +- `/pa modules install powerups`, activate per arena via +- `/pa [arenaname] !tm powerups` ## Setup -Sorry, but you have to add a freaking block to an arena config. An example is: +Sorry, but you have to add a freaking block to your arena config under `module.powerups.items`. E.g.: -powerups: +```yaml +items: - Shield: - item: OBSIDIAN - dmg_receive: @@ -108,12 +109,13 @@ powerups: - repair: - items: helmet,chestplate,leggins,boots - factor: 0.2 +``` So the first layer defines the name, the second layer defines item and adds all the effects it has. This example features all possible ways of doing good and bad things, I hope it is clear oO ## Config settings -- dropspawn \- should the powerup spawn require defined spawns? `/pa [arena] spawn powerupX +- dropspawn \- should the powerup spawn require defined spawns? `/pa [arena] spawn powerupX` (where X is an integer) - usage \- by default it is "off", so please set this to either every X kills ("death:X") or every X seconds ("time:X") ## Commands diff --git a/doc/mods/projectiles.md b/doc/mods/projectiles.md new file mode 100644 index 000000000..8b9aed5f1 --- /dev/null +++ b/doc/mods/projectiles.md @@ -0,0 +1,20 @@ +# Projectiles + +## About + +This module enables knockback effect for snowballs, eggs, fishing hooks and ender pearls in order to retrieve old spigot +behavior. + +## Setup + +There is no special setup for this module, follow the [general module installation](../modules.md#installing-modules) +guide to enable it. + +## Config settings + +*These settings can be found under `mods.projectiles` node in your arena config file.* + +- snowball - enable knockback for snowballs (default: true) +- egg - enable knockback for eggs (default: true) +- fishHook - enable knockback for fishing hooks (default: false) +- enderPearl - enable knockback for ender pearls (default: false) diff --git a/doc/mods/realspectate.md b/doc/mods/realspectate.md index 209706be6..50c96fb3f 100644 --- a/doc/mods/realspectate.md +++ b/doc/mods/realspectate.md @@ -8,7 +8,7 @@ Have players entering the arena and spectating the game from a player point of v Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/redstonetriggers.md b/doc/mods/redstonetriggers.md index b029881a1..f66b7e05d 100644 --- a/doc/mods/redstonetriggers.md +++ b/doc/mods/redstonetriggers.md @@ -8,7 +8,7 @@ This mod adds a redstone current change listener to eventually do things when a Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/respawnrelay.md b/doc/mods/respawnrelay.md index c0962ceba..e756b0f78 100644 --- a/doc/mods/respawnrelay.md +++ b/doc/mods/respawnrelay.md @@ -8,7 +8,7 @@ This mod puts respawns players in a "relay" spawn arena in order to respawn them Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/singleplayersupport.md b/doc/mods/singleplayersupport.md index 999541ccf..8671ed2ca 100644 --- a/doc/mods/singleplayersupport.md +++ b/doc/mods/singleplayersupport.md @@ -10,7 +10,7 @@ This module can be used for non-pvp game modes like parcour, where a player join Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/skins.md b/doc/mods/skins.md index 77dd44141..558b61d20 100644 --- a/doc/mods/skins.md +++ b/doc/mods/skins.md @@ -14,7 +14,7 @@ This module activates certain skins for teams / classes. IF you don't you disgui Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/specialjoin.md b/doc/mods/specialjoin.md index 47d45835c..e47e48b90 100644 --- a/doc/mods/specialjoin.md +++ b/doc/mods/specialjoin.md @@ -15,7 +15,7 @@ If you use the join sign, the fourth line will represent the arena status and th Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/spectate.md b/doc/mods/spectate.md index eba3494cb..da09656f7 100644 --- a/doc/mods/spectate.md +++ b/doc/mods/spectate.md @@ -10,7 +10,7 @@ Preventing interaction, damage, visibility, POV spectating and more :) Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/squads.md b/doc/mods/squads.md index 8f9f1a996..b2754492d 100644 --- a/doc/mods/squads.md +++ b/doc/mods/squads.md @@ -2,28 +2,38 @@ ## Description -This mod adds squads to the game, basically only showing players belonging together apart from teams and classes. +This mod allow players to make squads. Instead of respawning anywhere / at the team spawn, you spawn at a random squad member. + +Squads are an addition to teams or even a replacement (in case of a FFA arena). ## Installation Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` -## Setup +## Usage -\- +Place signs, similar to the Class Signs: + +``` +[Squad name] +[ignored] +free +free +``` + +You can add another (one) sign below for display of more player names -## Config settings ( config.yml !!! NOT per arena! ) +## Config settings ( in your arena config file ) - modules.squads.ingameSquadSwitch \- allow switching squads ingame ## Commands - `/pa [arena] !sq` \- show the arena squads -- `/pa [arena] !sq add [name]` \- add squad [name] -- `/pa [arena] !sq add [name] [limit]` \- add squad with player limit +- `/pa [arena] !sq add [name] [limit]` \- add squad with player limit (set to 0 to remove limit) - `/pa [arena] !sq remove [name]` \- remove squad [name] - `/pa [arena] !sq set [name] [limit]` \- set player limit for squad diff --git a/doc/mods/startfreeze.md b/doc/mods/startfreeze.md index ee728bcd8..82395bcdb 100644 --- a/doc/mods/startfreeze.md +++ b/doc/mods/startfreeze.md @@ -8,7 +8,7 @@ This module adds a timer that prevents people from moving at the start of a matc Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/teamsizerestrict.md b/doc/mods/teamsizerestrict.md index aec0d0a5a..b6195edb6 100644 --- a/doc/mods/teamsizerestrict.md +++ b/doc/mods/teamsizerestrict.md @@ -8,7 +8,7 @@ This mod adds player limitations to specific team names. Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/tempperms.md b/doc/mods/tempperms.md index b5f0edfde..12f86edb1 100644 --- a/doc/mods/tempperms.md +++ b/doc/mods/tempperms.md @@ -1,50 +1,53 @@ # TempPerms -## Description +## About -This module activates temporary permissins during a match. +This module activates temporary permission system during a match. You can set specific permissions to any player in the +arena or more specifically to a team or a class. -## Installation - -Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via +## Config settings -- `/pa install [modname]`, activate per arena via -- `/pa [arenaname] !tm [modname]` +There is no dedicated config setting for TempPerms, every permission you set are written in the perms part of your arena +configuration file. ## Setup -Either administrate via command OR create a config block inside the arena config, like this: +Either administrate via commands (recommended) OR complete the `perms` config block inside the arena config, like this: +```yaml perms: -- default: - - everyone.has.this - - ^everyone.doesnt.have.this -- blue: - - only.blue.has.this - - blue.does.not.have.this -- tank: - - tank.has.this - - ^tank.does.not.have.this - -Note that "-node" and "^node" are the same, just to clarify that you can use both :) - -## Config settings - -\- + - default: + - everyone.has.this + - -everyone.doesnt.have.this + - blue: + - only.blue.has.this + - -blue.does.not.have.this + - tank: + - tank.has.this + - -tank.does.not.have.this +``` + +
+ +> âš™ **Technical precision:** +> * For negative permissions, you can use either `-node` or `^node` syntax, it's the same thing. However when the config +> is saved, every negative permissions are rewritten with `-node` syntax. +> * `default` block contains permissions applied to every player ## Commands - `/pa [arena] !tps` \- list perms -- `/pa [arena] !tps add [perm]` \- add permission +- `/pa [arena] !tps add [perm]` \- add permission (normal or negative) - `/pa [arena] !tps rem [perm]` \- remove permission -- `/pa [arena] !tps [name]` \- list perms for class/team -- `/pa [arena] !tps [name] add [perm]` \- add permission for class/team -- `/pa [arena] !tps [name] rem [perm]` \- remove permission from class/team +- `/pa [arena] !tps [name]` \- list perms for a class/team +- `/pa [arena] !tps [name] add [perm]` \- add permission for a class/team +- `/pa [arena] !tps [name] rem [perm]` \- remove permission from a class/team -## Warnings +## Troubleshooting -Your permissions plugin needs to properly handle PermissionAttachments. If you experience this not working, double check if you GAVE superior permissions or SUB permissions that you didnt take away (explicitly), to be sure, add/remove eventual .* nodes and all subnodes. +If you experience this not working, double check if you GAVE superior permissions or SUB permissions that you didn't +take away (explicitly), to be sure, add/remove eventual .* nodes and all subnodes. ## Dependencies -Any superperms compatible permissions plugin +Any superperms compatible permissions plugin (like GroupManager, LuckyPerms, etc) diff --git a/doc/mods/titles.md b/doc/mods/titles.md index 478ce8c90..f2d358521 100644 --- a/doc/mods/titles.md +++ b/doc/mods/titles.md @@ -5,7 +5,7 @@ Change the way how messages are sent, by adding the vanilla "title" command func ## Installation Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/turrets.md b/doc/mods/turrets.md index bd3f3acef..deb4ffa84 100644 --- a/doc/mods/turrets.md +++ b/doc/mods/turrets.md @@ -10,7 +10,7 @@ To use the turret, step on the plate (during a match) and click. Aim where the p Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/vault.md b/doc/mods/vault.md index d6dd6124e..0039f5d8f 100644 --- a/doc/mods/vault.md +++ b/doc/mods/vault.md @@ -8,7 +8,7 @@ The Vault module adds an economy hook to provide several things. Join fee, money Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/walls.md b/doc/mods/walls.md index 4a742f998..816efc474 100644 --- a/doc/mods/walls.md +++ b/doc/mods/walls.md @@ -8,7 +8,7 @@ Yep. It's walls. Simple as can be. Make walls disappear ingame and reappear afte Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/mods/worldedit.md b/doc/mods/worldedit.md index f9fae1e58..5e5c3c133 100644 --- a/doc/mods/worldedit.md +++ b/doc/mods/worldedit.md @@ -1,15 +1,10 @@ # WorldEdit -## Description +## About -This module adds WorldEdit hooking for BATTLE region backup, restoring, even automatically +This module adds WorldEdit hooking for BATTLE [region](../regions.md) backup, restoring, even automatically. -## Installation - -Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via - -- `/pa install [modname]`, activate per arena via -- `/pa [arenaname] !tm [modname]` +You can also use this module to design your arena [regions](../regions.md) with a WorldEdit selection (cuboid shape only). ## Setup @@ -17,25 +12,34 @@ This module needs a full server restart to hook into WorldEdit properly, for the ## Config settings -- autoload \- automatically load the arena's BATTLE regions after fight -- autosave \- automatically save the arena's BATTLE regions before fight -- regions \- specify individual regions rather than all BATTLE regions +*These settings can be found under `mods.worldedit` node in your arena config file.* -## Commands +- autoload - automatically load the arena's BATTLE regions after fight (default: false) +- autosave - automatically save the arena's BATTLE regions before fight (default: false) +- regions - specify individual regions rather than all BATTLE regions (default: empty) +- schematicpath - the path where worldedit schematic files will be stored (default: root path) +- replaceair - if true, air blocks will be pasted on restore (default: true) +## Commands -- `/pa [arena] regload [regionname] {filename}` \- load the region -- `/pa [arena] regsave [regionname] {filename}` \- save the region +- `/pa [arena] regload [regionname]` \- load the region +- `/pa [arena] regsave [regionname]` \- save the region - `/pa [arena] regcreate [regionname]` \- create a region based on an active WorldEdit selection - `/pa [arena] !we autoload` \- toggle general automatic loading - `/pa [arena] !we autosave` \- toggle general automatic saving -- `/pa [arena] !we create [regionname]` \- create a region based on an active WorldEdit selection -(using this command creates a list of arena regions that will be saved/loaded) -## Warnings -\- +## Use case + +You just want to restore your arena after the match ? Just follow these instructions: +- Check the `schematicpath` setting to correspond to your directory tree +- Save your BATTLE region with command `/pa [arena] regsave [regionname]` +- Add the previously saved region name to `regions` setting (directly in your config file or via +[`/pa set`](../commands/set.md) command). +- Enable autoload with `/pa [arena] !we autoload` -## Dependencies +
-\- +> âš™ **Technical precision:** +> Worldedit pasting may freeze your server due to its working way. +> So be sure to regen only destroyable/buildable areas to reduce reloading time. diff --git a/doc/mods/worldguard.md b/doc/mods/worldguard.md index b7878837a..b243d90cb 100644 --- a/doc/mods/worldguard.md +++ b/doc/mods/worldguard.md @@ -8,7 +8,7 @@ This mod adds squads to the game, basically only showing players belonging toget Unzip the module files (files tab, "PA Files v*.*.*") into the /pvparena/files folder and install them via -- `/pa install [modname]`, activate per arena via +- `/pa modules install [modname]`, activate per arena via - `/pa [arenaname] !tm [modname]` ## Setup diff --git a/doc/modules.md b/doc/modules.md new file mode 100644 index 000000000..3cfd23f7e --- /dev/null +++ b/doc/modules.md @@ -0,0 +1,99 @@ +# PVP Arena Modules + +## About + +PvPArena modules are ways to enhance your arenas. They could modify a lot of things like configuration, fights, classes +or spectating... + +To manage your arena mods (download, install, remove, etc), please check [documentation](commands/modules.md) of +`/pa modules` command. + +## PVP Arena Mods + +Hook into many different aspects of the game! + +Mod | Description | Status +------------- | ------------- | ------------- +[AfterMatch](mods/aftermatch.md) | could also be called "Sudden Death" | âš  +[Announcements](mods/announcements.md) | announce events happening | âš  +[ArenaBoards](mods/arenaboards.md) | stats display | âš  +[ArenaMaps](mods/arenamaps.md) | never lose yourself ever again! | âš  +[AutoSneak](mods/autosneak.md) | automatically hide player nametags by forcing sneak mode | âš  +[AutoVote](mods/autovote.md) | automatism | âš  +[BanKick](mods/bankick.md) | secure your arenas! | âš  +[BattlefieldGuard](mods/battlefieldguard.md) | secure your battlefield | ✔ +[BattlefieldManager](mods/battlefieldmanager.md) | manage your battlefield | âš  +[BetterClasses](mods/betterclasses.md) | add potion effects and more to specific classes | ✔ +[BetterGears](mods/bettergears.md) | give team colored leather | ✔ +[BetterFight](mods/betterfight.md) | kill streaks and one-hit-kill items! | âš  +[BetterKillstreaks](mods/betterkillstreaks.md) | even more detailed kill streaks! | âš  +[BlockDissolve](mods/blockdissolve.md) | dissolve blocks under fighting players | ✔ +[BlockRestore](mods/blockrestore.md) | restore the battlefield | ✔ +[ChestFiller](mods/chestfiller.md) | fill battlefield chests with customizable content! | ✔ +[Duel](mods/duel.md) | duel someone! | âš  +[EventActions](mods/eventactions.md) | do stuff when stuff happens | âš  +[Factions](mods/factions.md) | fix pvp not working | âš  +[FixInventoryLoss](mods/fixinventoryloss.md) | prevent loss by gamemode / inventory check | âš  +[FlySpectate](mods/flyspectate.md) | have players spectating a fight in fly mode | ✔ +[Items](mods/items.md) | spawn (random) items | âš  +[LateLounge](mods/latelounge.md) | keep playing until enough ppl are joining | ✔ +[MatchResultStats](mods/matchresultstats.md) | keep stats of player games, who won, who lost? | âš  +[PlayerFinder](mods/playerfinder.md) | allow players to find others with a compass | ✔ +[Points](mods/points.md) | allow to restrict certain classes to require players to fight for better classes | âš  +[PowerUps](mods/powerups.md) | spawn items giving special powers | ✔ +[Projectiles](mods/projectiles.md) | add knockback to throwable items (snowballs, eggs, etc) | ✔ +[RealSpectate](mods/realspectate.md) | spectate the game, CounterStrike style! | ✔ +[RedstoneTriggers](mods/redstonetriggers.md) | add win/lose triggered by redstone | âš  +[RespawnRelay](mods/respawnrelay.md) | add a relay for respawning players | âš  +[SinglePlayerSupport](mods/singleplayersupport.md) | Allow players to use an arena on their own! | âš  +[Skins](mods/skins.md) | add custom skins to teams/classes | ⌠+[SpecialJoin](mods/specialjoin.md) | join via buttons, levers, etc | âš  +[Spectate](mods/spectate.md) | use the new 1.8 SPECTATOR mode to allow flying and POV spectating | âš  +[Squads](mods/squads.md) | add squads to the game, basically only showing players belonging together apart from teams and classes. | ✔ +[StartFreeze](mods/startfreeze.md) | freeze players at start | âš  +[TeamSizeRestrict](mods/teamsizerestrict.md) | a small mod to restrict the size of specific teams | âš  +[Titles](mods/titles.md) | send messages to players as the "title" command would do | ✔ +[TempPerms](mods/tempperms.md) | add temporary perms | ✔ +[Turrets](mods/turrets.md) | add turrets where players fire projectiles | âš  +[Vault](mods/vault.md) | add economy | ✔ +[Walls](mods/walls.md) | define wall regions to simulate "The Walls" | âš  +[WorldEdit](mods/worldedit.md) | backup/restore regions | ✔ +[WorldGuard](mods/worldguard.md) | import region definitions from WorldGuard | âš  + +**Key :** ✔ Recently tested and full-functional | âš  Legacy modules, not tested for a while | ⌠Temporarily unavailable + +### Why are there different statuses? + +PVP Arena exists since 2011 and Minecraft servers evolution make modules follow-up complicated. The objective of next +updates will be to make a great check-up of all of them and fix all eventual issues. + +Anyway, don't hesitate to test legacy modules by yourself, a big part of them work normally or have trivial issues. Obviously +if you encounter one, you can [report it](https://github.com/Eredrim/pvparena/issues) 😉 + +## Installing modules + +### Download the module pack + +> ℹ This has to be done only once + +Use the [`/pa modules download`](commands/modules.md) command to download the release version of modules. If you want to +install a dev build version, download the zip archive on [jenkins](https://ci.craftyn.com/job/PVP%20Arena%20Modules/) +and deflate it in the `/files` directory of pvparena. + +After this step, if you type [`/pa modules list`](commands/modules.md), you will show the list of all installable +modules. + +### Installing a module + +> ℹ This has to be done for each module you want to install + +Modules aren't loaded by default, a quick installation is required. +Type [`/pa modules install [moduleName]`](commands/modules.md) to install one of them. + + +### Enable a module for an arena + +> ℹ This has to be done for each arena + +Last step: your module is installed and you want to use it in some of your arenas. +Type [`/pa [arena] !tm [moduleName]`](commands/togglemod.md) to enable it in your arena. \ No newline at end of file diff --git a/doc/permissions.md b/doc/permissions.md index 89619397e..c9eb4f9af 100644 --- a/doc/permissions.md +++ b/doc/permissions.md @@ -1,4 +1,4 @@ -# Permission Nodes +# Permission nodes The following nodes can be used: @@ -10,18 +10,23 @@ pvparena.create| Allows you to create and administrate your arenas (default: op) pvparena.telepass| Allows you to teleport while in an arena (default: op) pvparena.user | Allows you to use the arena (default: true) -If you activate **explicitClassNeeded** you have to add permissions e.g. (proper class name case !!) + +### Specific class permissions + +If you activate `explicitClassNeeded` you have to add permissions e.g. (proper class name case !!) Node | Definition ------------- | ------------- pvparena.class.Ranger | Give Ranger class permission pvparena.class.Tank | Give Tank class permission -If you activate **explicitArenaNeeded** you have to add permissions e.g. (all lowercase!) +### Specific arena permissions + +If you activate `explicitArenaNeeded` you have to add permissions e.g. (all lowercase!) Node | Definition ------------- | ------------- pvparena.join.ctf | Give ctf join permission pvparena.join.spleef | Give spleef join permission -PVP Arena uses the SuperPerms interface \ No newline at end of file +PVP Arena uses the SuperPerms interface, i.e. default bukkit permissions interface. \ No newline at end of file diff --git a/doc/regions.md b/doc/regions.md index 879baf747..228a73920 100644 --- a/doc/regions.md +++ b/doc/regions.md @@ -1,45 +1,57 @@ # Regions -Regions allow further functions to be added to your game play. +Regions enhance your game play by adding protections, triggers or special configurations. -You can list existing arena regions with `/pa [arena] regions` +You can list existing arena regions with [`/pa [arena] regions`](commands/regions.md) ## Region Creation -All following commands assume you either have edit mode enabled or just one arena in place ! +*All following commands assume you either have edit mode enabled or just one arena in place.* + +Start creating an arena region with [`/pa region`](commands/region.md). -Start creating an arena region with `/pa !r` Now select a region by holding your arena wand (a STICK by default) and left click for position 1 and right click for position 2. Detailed information about the special region shapes, i.e. which points to select, check out the tutorial. -After selecting those points, use `/pa !r [regionname] [regionshape]` to save the region. -Region Shapes +After selecting those points, use [`/pa !r [regionname] [regionshape]`](commands/region.md) to save the region. -The following (self explanatory) region shapes exist: +The following region shapes exist: - CUBOID (default) - SPHERIC - CYLINDRIC -Of course, different shapes cover different areas. Note that a cylinder means a room like a can, so a standing cylinder. +Of course, different shapes cover different areas. Note that a cylinder means an area like a can, so a standing cylinder. -To remove a region, use `/pa region remove [regionname]` +To remove a region, use [`/pa !r [regionname] remove`](commands/region.md) ## Region Types -Set a region's type with `/pa !rt [regionname] [regiontype]` +Set a region's type with [`/pa !rt [regionname] [regiontype]`](commands/regiontype.md) The following Region Types exist: - CUSTOM (default) => does nothing -- WATCH => is the place where spectators should be, BattleFieldGuard will kick spectators not being part inside of one WATCH region -- LOUNGE => is the place where fighters select their class. It currently has no use, but might do in the future +- WATCH => the place where spectators should be, BattleFieldGuard will kick spectators not being part inside of one WATCH region +- LOUNGE => the place where fighters select their class. Required to allow players interactions in the lounge. - BATTLE => the most important type. It adds battlefield reservation (for overlapping arenas, only caring about that actually battle region), region protection, restoring and check if fighters are in the right place. - EXIT => the region where players should be after exiting the arena, no functionality atm - JOIN => the region where players should be when joining, see Configuration page, enforcement is disabled by default - SPAWN => a spawn region where players are randomly placed in when spawning or respawning +- BL_INV => block chest access to any team which name is included in the region name, same for classes +- WL_INV => restrict chest access to each team which name is included in the region name, same for classes + +#### Usage of BL_INV and WL_INV + +For these regions types, the name of the region is important. It is read by the plugin to understand access restrictions. + +Example: +* Region name is `RedBlueRanger` and region type is `WL_INV` => allows Red or Blue teams or Ranger class to access chests. +* Region name is `xxblueyy` and region type is `BL_INV`=> disallow chest access to the blue team ## Region Flags -Further customisation of region functionality with `/pa !rf [regionname] [regionflag]` +You can enable special player interactions with players by using regions flags. +Just use the command [`/pa !rf [regionname] [regionflag]`](commands/regionflags.md). + Those are valid Region Flags: - NOCAMP - players that don't move inside this region will be hurt @@ -50,18 +62,32 @@ Those are valid Region Flags: ## Region Protection -The BATTLE Region parses region protection flags (other regions can assigned protections, too, but atm they don't really use them). Set them via `/pa !p [regionname] [protection]` - you can add on, off, yes, no, true, false to specify a setting, or just as just told to toggle the state. Note that there is an "ALL" protection node that triggers/sets all protection nodes -Valid protections are: +The BATTLE Region parses region protection flags (other regions can assigned protections, too, but atm they don't +really use them). Set them via [`/pa !p [regionname] [protection]`](commands/protection.md) - you can add on, off, yes, +no, true, false to specify a setting, or just as just told to toggle the state. -- BREAK - Block breaking -- FIRE - Fire (spreading) -- MOBS - Mob spawning -- NATURE - Environment changes (leaves, shrooms, water, lava) -- PAINTING - Painting placement/destruction -- PISTON - Piston triggering -- PLACE - Block placement -- REDSTONE - Redstone current change -- TNT - TNT usage -- TNTBREAK - TNT block break -- TELEPORT - Players Teleportation +Valid protections are: +- BREAK - prevent player block breaking +- FIRE - prevent fire spreading/burning +- MOBS - prevent mob spawning +- NATURE - prevent water flow/growth +- PAINTING - prevent painting/itemframe breakage +- PISTON - prevent piston usage +- PLACE - prevent player block placing +- TNT - prevent tnt interaction +- TNTBREAK - prevent tnt block damage (explosion still hurts) +- DROP - prevent player item dropping +- INVENTORY - prevent inventory interaction +- PICKUP - prevent player item pickup +- TELEPORT - prevent player teleportation + +Example: `/pa !p main break on` - disallow players to break blocks in "main" region of your arena + +> 🚩 **Tip:** +> There is an "ALL" protection argument that toggle all protections + +## Region Removal + +First, you need to know the region name. List regions with `/pa [arenaname] regions`. +Then, use `/pa [arenaName] region [regionname] remove` to remove the region. diff --git a/doc/update-checker.md b/doc/update-checker.md new file mode 100644 index 000000000..3c03d5b48 --- /dev/null +++ b/doc/update-checker.md @@ -0,0 +1,15 @@ +# Update Checker + +If you want you can be informed of plugin or modules updates. Each release version was pushed on github since 1.14.0. +The update checker will call the github APIs and announce an update to OPs on login. You can configure it to +automatically download updates. + +```yaml + update: + plugin: announce + modules: announce + # valid values: + # download: download updates and announce when update is installed + # announce: only announce, do not download + # everything else will disable the update check +``` diff --git a/doc/update-version.md b/doc/update-version.md new file mode 100644 index 000000000..5d7f59117 --- /dev/null +++ b/doc/update-version.md @@ -0,0 +1,108 @@ +# Upgrading from 1.14.x + +If you want to upgrade your arena configurations to PVPArena 1.15 version or above, please update +these two things : + +## Goal PhysicalFlags + +If you use *physicalFlags* goal for your arenas, just rename `flags` block to `physicalFlags` in +your config file. + +Example : + +*Replace this* +```yaml +goal: + endCountDown: 5 + flags: + flives: 3 + mustBeSafe: true + woolFlagHead: true + effect: none + flagType: WHITE_WOOL +``` +*with this* +```yaml +goal: + endCountDown: 5 + physicalFlags: + flives: 3 + mustBeSafe: true + woolFlagHead: true + effect: none + flagType: WHITE_WOOL +``` + +## Goal checkpoints + +In checkpoint goal, checkpoint indexes started at 0, now they start at 1. Just edit your config +file and decrease all checkpoints number by one in `spawns` block. + +Example : + +*Replace this* +```yaml +spawns: + checkpoint0: world,299,64,1276,-357.7568359375,4.2000017166137695 + checkpoint1: world,299,64,1276,11.695333480834961,22.20012664794922 + checkpoint2: world,300,64,1281,-5.704666614532471,23.700136184692383 + checkpoint3: world,297,64,1285,14.695302963256836,50.40021514892578 + checkpoint4: world,298,64,1289,53.69533920288086,54.75028610229492 + checkpoint5: world,295,64,1292,1.795335054397583,46.80023193359375 +``` +*with this* +```yaml +spawns: + checkpoint1: world,299,64,1276,-357.7568359375,4.2000017166137695 + checkpoint2: world,299,64,1276,11.695333480834961,22.20012664794922 + checkpoint3: world,300,64,1281,-5.704666614532471,23.700136184692383 + checkpoint4: world,297,64,1285,14.695302963256836,50.40021514892578 + checkpoint5: world,298,64,1289,53.69533920288086,54.75028610229492 + checkpoint6: world,295,64,1292,1.795335054397583,46.80023193359375 +``` + +## PowerUps Module + +In powerups mod, items and effects configuration was previously in a dedicated `powerups` bloc at root of your arena +config files. Just move this block content into a the following path `modules.powerups.items` + +Example : + +*Replace this* +```yaml +powerups: + Heal: + item: BREAD + health: + diff: 3 + Repair: + item: WORKBENCH + repair: + items: helmet,chestplate,leggins,boots + factor: 0.2 +# Lines below have no importance +teams: + red: RED + blue: BLUE +``` +*with this* +```yaml +modules: + powerups: + dropspawn: true + usage: death:1 + items: + Heal: + item: BREAD + health: + diff: 3 + Repair: + item: WORKBENCH + repair: + items: helmet,chestplate,leggins,boots + factor: 0.2 +# Lines below have no importance +teams: + red: RED + blue: BLUE +``` \ No newline at end of file diff --git a/lang/lang_en.yml b/lang/lang_en.yml new file mode 100644 index 000000000..02d6902f2 --- /dev/null +++ b/lang/lang_en.yml @@ -0,0 +1,663 @@ +nulang: + arena: + create: + done: arena '%1%' created! + disable: + done: Arena disabled! + edit: + disabled: 'Disabled edit mode for arena: %1%' + enabled: 'Enabled edit mode for arena: %1%' + enable: + done: Arena enabled! + arenalist: 'Arenas: &a%1%&r' + regionshapeunknown: 'Arena Shape ''%1%'' unknown. consult the forums: http://goo.gl/IfLOh' + reload: + done: Arena reloaded! + remove: + done: 'Arena removed: &e%1%&r' + setup: + disabled: 'Disabled setup mode for arena: %1%' + enabled: 'Enabled setup mode for arena: %1%' + startingin: Enough players ready. Starting in %1%! + start: + done: Arena force started! + stop: + done: Arena force stopped! + autosetup: + automanual: Do you want the wizard to be &a%1%&r or &a%2%&r? + automatic: automatic + manual: manual + modeselected: '&a%1%&r mode selected!' + welcome: |- + Welcome to the PVP Arena setup wizard! + Please just type the colored answers into the chat. No commands needed! + blacklist: + added: Added &a%1%&r to &e%2%&r blacklist! + allcleared: All blacklists cleared! + cleared: Blacklist &e%1%&r cleared! + help: 'Usage: blacklist clear | blacklist [type] [clear|add|remove] [id]' + removed: Removed &a%1%&r from &e%2%&r blacklist! + show: 'Blacklist &e%1%&r:' + check: + done: Check done! No errors! + class: + list: 'Available classes: %1%' + preview: You are now previewing the class %1% + removed: 'Class removed: %1%' + saved: 'Class saved: %1%' + selected: You have switched to &e%1%&e class + selectedrespawn: You will switch to the &e%1%&f class on next respawn. + deathcause: + BLOCK_EXPLOSION: an explosion + CONTACT: a cactus + CUSTOM: Herobrine + DROWNING: water + ENTITY_EXPLOSION: an Explosion + FALL: gravity + FIRE_TICK: fire + FIRE: a fire + LAVA: lava + LIGHTNING: Thor + MAGIC: Magical Powers + POISON: Poison + PROJECTILE: something he didn't see coming + STARVATION: hunger + SUFFOCATION: lack of air + SUICIDE: self + THORNS: thorns + VOID: the Void + FALLING_BLOCK: a falling block + HOT_FLOOR: a magma block + CRAMMING: a collision surplus + DRAGON_BREATH: dragon breath + CREEPER: a creeper + SKELETON: a skeleton + SPIDER: a spider + GIANT: a giant + ZOMBIE: a zombie + SLIME: a slime + GHAST: a ghast + PIG_ZOMBIE: a pig zombie + ENDERMAN: an enderman + CAVE_SPIDER: a cave spider + SILVERFISH: silverfish + BLAZE: a blaze + MAGMA_CUBE: a magma cube + ENDER_DRAGON: an ender dragon + WITHER: a wither boss + WITCH: a witch + WOLF: a wolf + IRON_GOLEM: an iron golem + SPLASH_POTION: a splash potion + duty: + 'false': You are now off duty! + 'true': You are now on duty! + error: + arena: + alreadyplaying: You are already part of &a%1%&r + arenaexists: Arena already exists! + arenanotexists: 'Arena does not exist: %1%' + arenaconfig: 'Error when loading arena config: %1%' + argumenttype: '&cInvalid argument type:&r &e%1%&r is no proper &a%2%&r' + argument: '&cArgument not recognized:&r %1% - possible arguments: &a%2%&r' + autosetup: + running: 'There is already an autosetup running! Player: %1%' + blacklist: + disallowed: You may not %1% this! Blacklisted! + unknownsubcommand: 'Unknown subcommand. Valid commands: &a%1%&r' + unknowntype: 'Unknown type. Valid types: &e%1%&r' + class: + full: The class &a%1%&r is full! + notenoughexp: You don't have enough EXP to choose &a%1%&r! + notfound: 'Class not found: &a%1%&r' + cmdblocked: '&cCommand blocked: %1%' + invalidcmd: Invalid command (%1%) + unknowncmd: Unknown command + arenadisabled: Arena disabled, please try again later! + editmode: edit mode! + error: '&cError: %1%' + fightinprogress: A fight is already in progress! + goal: + legacyunknown: 'Legacy goal &a%1%&r unknown! You will want to add goals: &a/pa + [arena] goal [goalname]' + goalnotfound: 'Goal &a%1%&r unknown. Valid goals: &a%2%&r' + install: Error while installing &a%1%&r + invalid_argument_count: '&cInvalid number of arguments&r (%1% instead of %2%)!' + invalidstattype: 'Invalid statistics type: %1%' + valuenotfound: 'Invalid value: &a%1%&r!' + invfull: Your inventory was full. You did not receive all rewards! + arenafull: arena is full! + joinrange: You are too far away to join this arena! + notjoinregion: You are not in the join region! Move there to join! + teamfull: team %1% is full! + insidevehicle: You cannot join while on a vehicle! + errorloungefree: Error! Arena is not of type free. Use '[teamname]lounge' + log: + matnotfound: 'Unrecognized material: %1%' + missingspawn: 'Spawn missing: &f%1%' + noarenas: No arenas found! + valueneg: 'Negative values: &c%1%&r' + nofight: There is no fight in progress. + nogoal: You did not add a goal! &a/pa [arena] goal [goalname] + nospawns: No spawns set! + classperms: You do not have permission for class &a%1%&r + permjoin: You don't have permission to join the arena! + noperm: '&cNo permission to %1%' + noplayerfound: No player found! + notinarena: You are not part of an arena! + notnumeric: '&cArgument not numeric:&r %1%' + notsameworld: Not in the same world as the arena (%1%)! + noteamfound: No team found! + onlyplayers: '&cThis command can only be used by players!' + playernotfound: '&cPlayer not found: &f%1%&c!' + positives: 'Positive values: &b%1%&r' + potioneffecttypenotfound: 'PotionEffectType not found: &e%1%&r' + ready: + notready0: At least one player is not ready! + notready1: You are alone in the arena! + notready2: Your team is alone in the arena! + notready3: A team is missing players! + notready4: The arena is missing players! + notready5: At least one player has not chosen a class! + noclass: You don't have a class! + error: The arena is not ready! %1% + region: + beingcreated: 'A region is already being created: %1%' + flagnotfound: 'RegionFlag &a%1%&r unknown! Valid values: %2%' + notfound: Region &a%1%&r not found! + protectionnotfound: RegionProtection &a%1%&r unknown! + typenotfound: 'RegionType &a%1%&r unknown! Valid values: %2%' + youselect: You are already selecting a region for an arena! + youselect2: Type the command again to cancel selection mode! + youselectexit: Region selection cancelled! + regionnotbeingcreated: A region is not being created! + regionnotremoved: There is no region setup. + select2: Select two points before trying to save. + setupmode: setup mode! + spawn: + unknown: 'Unknown spawn: &a%1%&r' + spawnfree: Error! Arena is of type free. Use 'spawnX' where X is a digit or letter! + statsfile: Error while reading the stats file! + teamnotfound: 'Team not found: &a%1%&r' + uninstall: Error while uninstalling &a%1%&r + unknownmodule: 'Module not found: %1%' + whitelist: + disallowed: You may not %1% this! (not whitelisted) + unknownsubcommand: 'Unknown subcommand. Valid commands: &a%1%&r' + unknowntype: 'Unknown type. Valid types: &e%1%&r' + nopermto: + madmin: administrate + create: create an arena + disable: disable + edit: edit an arena + enable: enable + nopermjoin: join an arena + reload: reload + remove: remove an arena + set: set a config node + setup: setup an arena + teleport: teleport to an arena spawn + user: use PVP Arena + cmds: + blacklist: use the blacklist command + check: use the check command + class: use the class command + create: use the create command + debug: use the debug command + disable: use the disable command + duty: use the duty command + edit: use the edit command + enable: use the enable command + gamemode: use the gamemode command + goal: use the goal command + playerclass: use the playerclass command + playerjoin: use the playerjoin command + protection: use the protection command + region: use the region command + regionflag: use the regionflag command + regions: use the regions command + regiontype: use the regiontype command + reload: use the reload command + remove: use the remove command + round: use the round command + set: use the set command + setowner: use the setowner command + setup: use the setup command + spawn: use the spawn command + start: use the start command + stop: use the stop command + teams: use the teams command + teleport: use the teleport command + template: use the template command + togglemod: use the togglemod command + modules: use the modules command + whitelist: use the whitelist command + arenaclass: use the arenaclass command + chat: use the chat command + join: use the join command + leave: use the leave command + spectate: use the spectate command + arenalist: use the arenalist command + help: use the help command + info: use the info command + list: use the list command + ready: use the ready command + shutup: use the shutup command + stats: use the stats command + version: use the version command + fight: + begins: Let the fight begin! + draw: This match was a draw! No winners! + killedbyremaining: '%1% has been killed by %2%! %3% lives remaining.' + killedbyremainingfrags: '%1% has been killed by %2%! %3% kills remaining.' + killedbyremainingteam: '%1% has been killed by %2%! %3% lives remaining for %4%.' + killedbyremainingteamfrags: '%1% has been killed by %2%! %3% kills remaining for + %4%.' + killedby: '%1% has been killed by %2%!' + playerleft: '%1% has left the fight!' + forcestop: You have forced the fight to stop. + gamemode: + free: Game mode &afree for all&r set for arena &a%1%&r! + team: Game mode &ateam&r set for arena &a%1%&r! + general: + break: break + place: place + use: use + goal: + added: 'Goal added: &a%1%&r' + installing: 'Install goals by command: &a/pa install [goalname]&r' + removed: 'Goal removed: &a%1%&r' + blockdestroy: + typeset: 'Blocktype set to: &e%1%' + setflag: 'Block set: %1%' + tosetflag: 'Block to set: %1%' + dom: + bossbar_claiming: 'Claiming...' + bossbar_unclaiming: 'Unclaiming...' + claiming: '&eTeam %1% is claiming a flag!' + claimed: '&eTeam %1% has claimed a flag!' + score: '&eTeam %1% scored %2% points by holding a flag!' + contesting: '&eA flag claimed by team %1% is being contested!' + unclaiming: '&eA flag claimed by Team %1% is being unclaimed!' + unclaimingby: '&eA flag claimed by Team %1% is being unclaimed by Team %2%!' + infected: + lost: '&6The infected players have been killed!' + player: '&c%1% is infected!' + you: '&cYou are infected!' + won: '&6The infected players have won the game!' + iprotect: 'The infected team is prevented from: %1%' + iprotectset: '&ePlayerProtection &f%1%&f set to: %2%' + killreward: + added: 'Kill reward added: &e%1%&f->&a%2%' + removed: 'Kill reward removed: &e%1%' + liberation: + liberated: Team %1% has been liberated! + setbutton: 'Button set: %1%' + tosetbutton: 'Button to set: %1%' + physicalflags: + holdflag: You have to hold the flag to bring it back! + sabotage: + tntignite: '%1% ignited the TNT of team %2%!' + set: 'TNT set: %1%' + toset: 'TNT to set: %1%' + noselfdestroy: 'You can not ignite your own TNT!' + youtnt: 'You now carry the sabotage tool!' + notgooditem: 'You need sabotage tool to ignite the TNT.' + tank: + tankdown: The tank is down! + tankmode: TANK MODE! Everyone kill %1%, the tank! + tankwon: The tank has won! Congratulations to %1%! + tdc: + denied: '%1% denied a kill!' + remaining: '%1% kills remaining for %2%.' + scored: '%1% scored a kill!' + youdenied: You denied a kill! + youscored: You scored a kill! + pillars: + msg: + block_broken: '[%1%] %2% broke a block!' + lower: '[%1%] %2% shortened the pillar!' + block_placed: '[%1%] %2% placed a block!' + higher: '[%1%] %2% lengthened the pillar!' + claimed: '[%1%] %2% claimed the pillar!' + unclaimed: '[%1%] %2% unclaimed the pillar!' + score: '%1% scored %2% points' + help: + head: '&e--- &aPVP Arena Help&e %1% &e---' + admin: '&c%1% - help administrating' + setup: '&e%1% - help setting up' + custom: '&e%1% - help customizing' + game: '&a%1% - help ingame' + info: '&9%1% - help getting information' + import: + done: Successfully imported arena &e%1%&r! + info: + classes: 'Classes: &a%1%&r' + goal_active: 'Goal: &a%1%&r' + goal_inactive: 'Goal: &b%1%&r &7== INACTIVE ==' + head_headlin: 'Arena Information about: &a%1%&r | [&a%2%&r]' + head_teams: 'Teams: &a%1%&r' + mod_active: 'Module: &a%1%&r' + mod_inactive: 'Module: &b%1%&r &7== INACTIVE ==' + owner: 'Owner: &a%1%&r' + regions: 'Regions: &a%1%&r' + section: '----- &a%1%&r -----' + install: + installed: 'installed: &a%1%&r' + list: + arenas: 'Available arenas: %1%' + dead: 'Dead: %1%' + fighting: 'Fighting: %1%' + lost: 'Lost: %1%' + lounge: 'Lounge: %1%' + 'null': 'Glitched: %1%' + players: 'Players: %1%' + team: 'Team %1%: %2%' + ready: 'Ready: %1%' + warm: 'Warm: %1%' + watching: 'Watching: %1%' + log: + plugindisabled: disabled (version %1%) + pluginenabled: enabled (version %1%) + trickerdisabled: Plugin tracking disabled. See you soon? + trackingenabled: 'Plugin tracking enabled. Set tracker: false inside the main + config to disable.' + updatedisabled: Updates deactivated. Please check dev.bukkit for updates. + updateenabled: Checking for updates... + warning: '%1%' + messages: + toArena: You are now talking to the arena! + toPublic: You are now talking to the public! + toTeam: You are now talking to your team! + general: '&e[%1%&e] &f%2%' + noplayer: No player in the PVP arena. + notice: + awarded: You have been awarded %1% + nodropitem: Not so fast! No cheating! + noteleport: Please use '/pa leave' to exit the fight! + notice: 'Notice: %1%' + playerawarded: '%1% has been awarded %2%' + remove: '&cThis will permanently remove the arena &a%1%&c. Are you sure? Then + commit the command again!&f To disable this message, see ''safeadmin'' in your + config.yml' + waitingequal: Waiting for the teams to have an equal player number! + waitingforarena: Waiting for a running arena to finish! + welcomespec: Welcome to the spectator's area! + gameloot: Here is your game loot! + welcomespec2: /pa bet [name] [amount] to bet on team or player + youdeath: You entered a DEATH region. Goodbye! + youescaped: You escaped the battlefield. Goodbye! + youleft: You left the arena! + younocamp: You are in a NOCAMP region. Move! + playerhaswon: '%1% is the Champion!' + playerready: '%1%&e is ready!' + player: + prevented: + break: '&cYou may not break blocks!' + place: '&cYou may not place blocks!' + tnt: '&cYou may not use TNT!' + tntbreak: '&cYou may not break TNT!' + drop: '&cYou may not drop items!' + inventory: '&cYou may not access this!' + craft: '&cYou may not craft!' + notreadyplayers: Players not ready + players: Players + ready: + list: 'Players: %1%' + done: You have been flagged as ready! + region: + flag: + added: 'Region flag added: &a%1%&r' + removed: 'Region flag removed: &a%1%&r' + height: 'Region height set to: &a%1%&r' + pos1: First position set. + pos2: Second position set. + protection_added: 'RegionProtection added: &a%1%&r' + protection_removed: 'RegionProtection removed: &a%1%&r' + radius: 'Region radius set to: &a%1%&r' + removed: 'Region removed: %1%' + saved: Region saved. + saved_notice: '&6You created a &oCUSTOM&6 region. It has no function yet! To turn + it into a battlefield region, type &r/pvparena %1% !rt %2% BATTLE.' + select: Select two points with your wand item, left click first and then right click! + setting: Setting region enabled. + typeset: 'Region Type set: &e%1%' + youselect: You are now selecting a region for arena &a%1%&r! + regions: + flags: 'Region Flags: &a%1%&r' + head: '--- &aArena Region&r [&e%1%&r]---' + listhead: '--- &aArena Regions&r [&e%1%&r]---' + listvalue: '&a%1%&r: %2%, %3%' + protections: 'Region Protections: &a%1%&r' + shape: 'Region Shape: &a%1%&r' + type: 'Region Type: &a%1%&r' + reloaded: Config reloaded! + round: + display: 'Round #%1%: %2%' + added: 'Added goal to round: &e%1%' + removed: 'Removed goal from round: &e%1%' + set: + done: '&a%1%&r set to &e%2%&r!' + help: use /pa {arenaname} set [page] to get a node list + unknown: 'Unknown node: &e%1%&r!' + setowner: + done: '&a%1%&r is now owner of arena &a%2%&r!' + spawn: + freelounge: Lounge set + teamlounge: 'Lounge set: %1%' + notset: 'Spawn not set: &a%1%&r' + offset: Spawn &a%1%&r offset by &a%2%&r blocks. + removed: 'Spawn removed: &a%1%&r' + set: 'Spawn set: &a%1%&r' + setdone: 'Spawn setting done: &a%1%&r' + setstart: 'Spawn setting started: &a%1%&r' + unknown: 'Spawn not found: &a%1%&r' + stats: + filedone: Statistics file loaded! + head: Statistics TOP %1% (%2%) + typenotfound: 'Statistics type not found! Valid values: &e%1%&r' + stattype: + DAMAGE: full damage dealt + DAMAGETAKE: full damage taken + DEATHS: deaths + KILLS: kills + LOSSES: matches lost + MAXDAMAGE: max damage dealt + MAXDAMAGETAKE: max damage taken + 'NULL': player name + WINS: matches won + team: + haswon: Team %1% are the Champions! + ready: Team %1% is ready! + teams: + list: 'Available teams: %1%' + add: 'Team added: %1%' + set: 'Team set: %1%' + remove: 'Team removed: %1%' + template: + loaddone: 'Template loaded from: &a%1%&r' + savedone: 'Template saved to: &a%1%&r' + time: + minutes: minutes + seconds: seconds + timer: + countdowninterrupt: Countdown interrupted! Hit the ready block! + ending: The match will end in %1%! + resetting: The arena will reset in %1%! + starting: Starting in %1%! + warmingup: Warming up... %1%! + pvpactivating: PVP will be activated in %1%! + walls: Walls will be removed in %1%! + togglemod: + notice: '&cYou activated a module that requires a BATTLE region! Type: &r/pvparena + [arena] !rt [region] BATTLE' + uninstall: + done: 'uninstalled: &a%1%&r' + whitelist: + added: Added &a%1%&r to &e%2%&r whitelist! + allcleared: All whitelist cleared! + cleared: Whitelist &e%1%&r cleared! + help: 'Usage: blacklist clear | blacklist [type] [clear|add|remove] [id]' + removed: Removed &a%1%&r from &e%2%&r whitelist! + show: 'Whitelist &e%1%&r:' + mod: + aftermatch: + aftermatch: The aftermatch has begun! + startingin: AfterMatch in %1%! + spawnnotset: Spawn 'after' not set! + announcements: + ignoreon: You are now ignoring announcements! + ignoreoff: You are now receiving announcements! + arenaboards: + createarenaboard: create an ArenaBoard + arenaboarddestroyed: ArenaBoard destroyed! + boardexists: ArenaBoard already exists!' + sortingby: ArenaBoard now sorted by %1% + autovote: + arenarunning: 'Arena running: %1%' + autojoin: Arena auto join started! + playervoted: '%2% voted for arena %1%!' + youvoted: You voted for arena %1%! + duel: + accepted: '%1% &eaccepted the challenge! The game is starting.' + announce: '%1% &echallenged you! Accept the duel with &f/pa %2% accept.' + announce2: '&eCancel the duel with &r/pa %2% decline&e.' + busy: '%1% &eis already in a fight Please try again later.' + declineds: Your opponent declined the request. The duel has been cancelled. + declinedr: You declined the duel request! + requested: You &echallenged &r%1%&e! + requestedalready: You already have challenged someone! + requestexpireds: Your opponent did not accept the request in time. The duel has been cancelled. + requestexpiredr: You did not accept the request in time. The duel has been cancelled. + starting: The duel begins! + nodirectjoin: 'You may not join this arena directly! Use: &e/pa %1% duel [playername]' + fixinventorylos: + gamemode: Enter survival gamemode before joining! + invenory: Empty your inventory before joining! + latelounge: + llannounce: Arena %1% is starting! Player %2% wants to start. Join with /pa %1% + llposition: You are on queue position %1%! + llrejoin: Ready check has caught you not being able to join. Rejoin when you can! + llwait: Arena will be starting soon, please wait! + llleave: You have left the queue of the %1% arena. + playerfinder: + near: 'Nearest player: %1% blocks!' + point: Compass pointing to nearest player! + powerups: + invalidpowerupeffect: 'Invalid PowerupEffect: %1%' + puplayer: '%1% has collected PowerUp %2%!' + puserver: PowerUp deployed! + respawnrelay: + respawning: Respawning in %1%! + skins: + dc: Hooking into DisguiseCraft! + md: Hooking into MobDisguise! + nomod: No disguise plugin found, Skins module is inactive! + showclass: Class &e%1%&r will be disguised to &a%2% + showteam: Team %1% will be disguised to %2% + specialjoin: + done: Join block set here - %1% + start: Setting join block! + stop: Aborted join block selection! + squads: + nosquad: 'No squads loaded! Add some: /pa [arena] !sq add [name]' + listhead: Squads for arena &b%1% + listitem: 'Squad %1% (max: %2%) %3%' + added: Squad %1% has been added + set: Squad %1% has been set + removed: Squad %1% has been removed + notexist: Squad %1% doesn't exist + error: Error while editing squads, syntax is not correct! + full: This squad is full! + help: |- + /pa !sq | show the arena squads + /pa !sq add [name] [limit] | add squad with player limit (set to 0 for no limit) + /pa !sq set [name] [limit] | set player limit for squad + /pa !sq remove [name] | remove squad [name] + startfreeze: + announce: The game will start in %1% seconds! + tempperms: + noperms: Permissions plugin not found, defaulting to OP. + head: 'Temporary permissions of &e%1%&r:' + added: Temporary permissions &e%1%&r added to &a%2%&r + removed: Temporary permissions &e%1%&r removed from &a%2%&r + vault: + 'on': <3 eConomy + 'off': %1%! + unknownsubcommand: 'Sub-Comando Desconocido. Comandos validos: &a%1%&r' + unknowntype: 'Tipo Desconocido. Tipos validos: &e%1%&r' + class: + full: ¡La Clase &a%1%&r esta llena! + notenoughexp: ¡No tienes Nivel suficiente para escojer &a%1%&r! + notfound: 'Clase no encontrada: &a%1%&r' + cmdblocked: '&cComando bloqueado: %1%' + invalidcmd: Comando Inválido (%1%) + unknowncmd: Comando Desconocido + arenadisabled: Arena deshabilitada, por favor intenta otra vez luego :c + editmode: Modo edición ¬¬ + error: '&cError: %1%' + fightinprogress: ¡Hay una partida en progreso! + goal: + legacyunknown: '¡Objetivo (Goal) ingresada: "&a%1%&r" desconocida! Si deseas + añadir objetivos utiliza el comando: &a/pa [Arena] goal [Nombre del Objetivo + (goal)]' + goalnotfound: 'Objetivo &a%1%&r desconocido. Objetivos validos: &a%2%&r' + install: Error mientras se instalaba &a%1%&r + invalid_argument_count: '&cNúmero inválido de Argumentos&r (%1% en lugar de + %2%)!' + invalidstattype: 'Tipo de Estadística inválido: %1%' + valuenotfound: 'Valor inválido: &a%1%&r!' + invfull: ¡Tu inventario esta lleno, no recibiste tu recompensa! + arenafull: ¡La Arena esta llena :c! + joinrange: ¡Estas muy lejos de el Arena para unirse de la Arena! + notjoinregion: ¡No estas en el lugar correcto para unirse a la Arena! Ve allí para unirte. + teamfull: ¡El Equipo %1% esta lleno! + insidevehicle: ¡No puedes unirte a una Arena mientras estas en un Bote/Minecart/Caballo/Cerdo/ vehículos en general! + errorloungefree: ¡Error la Arena no esta en el modo sin equipos (free mode). Utiliza '[Nombre del equipo en Inglés Ejemplo Blue, Red, etc.]lounge' + log: + matnotfound: 'Material incorrecto: %1%' + missingspawn: 'Lugar de Reaparición(Spawn) no encontrado: &r%1%' + noarenas: ¡No tienes ninguna Arena! + valueneg: 'Valores Negativos: &c%1%&r' + nofight: No hay ninguna Partida/Batalla en progreso. + nogoal: ¡No has añadido ningún Objetivo(goal) para la Arena! Utiliza el comando &a/pa [Nombre de la Arena] goal [Nombre del Objetivo(goal)] para añadir uno + nospawns: ¡No se ha añadido ningún Lugar de Aparición(Spawn) para la Arena! + classperms: No tienes permisos para utilizar la Clase "&a%1%&r" + permjoin: You don't have permission to join the arena! + noperm: '&cNo tienes permisos para %1%' + noplayerfound: ¡No jugadores encontrados! + notinarena: ¡No eres parte de ninguna Arena! + notnumeric: '&cArgumento no numerico:&r %1%' + notsameworld: ¡No estas en el mismo Mundo de la Arena (%1%)! + noteamfound: ¡Equipos no encontrados! + onlyplayers: '&cEste comando solo puede ser utilizado por los Jugadores! &4Así + que no seas perezoso y no lo vuelvas a hacer desde el cmd ¬¬' + playernotfound: '&cJugador no encontrado: &r%1%&c!' + positives: 'Valores Positivos: &b%1%&r' + potioneffecttypenotfound: 'Efecto de poción: &e%1%&r no encontrado/reconocido' + ready: + notready0: No hay ningún jugador listos + notready1: Estas solo en la Arena :c + notready2: Tu Equipo esta solo en la Arena + notready3: A un Equipo le falta jugaores + notready4: A la Arena le falta Jugadores + notready5: Al menos un Jugadores no ha elejido ninguna clase aún + noclass: ¡No has elejido clase! + error: La Arena no esta lista/A la arena le falta %1% + region: + beingcreated: Ya hay una Región creada con el mismo nombre (%1%) + flagnotfound: '¡RegionFlag &a%1%&r desconocido! Valores válidos: %2%' + notfound: Región &a%1%&r no encontrada + protectionnotfound: ¡RegionProtection &a%1%&r desconocido! + typenotfound: 'RegionType &a%1%&r desconocido! Valores válidos: %2%' + youselect: Ya esas seleccionando una Región (Para dejar de Seleccionar escribe el Comando otra vez) + youselect2: Escribe el Comando una vez más para cancelar la selección de la Región + youselectexit: Selección de Región cancelada! + regionnotbeingcreated: ¡No estas creando una Región! + regionnotremoved: No hay ninguna configuración de región. + select2: Seleccione dos puntos antes de tratar de guardar. + setupmode: ¡Modo de Configuración! + spawn: + unknown: 'Lugar de reaparición (spawn) desconocido: &a%1%&r' + spawnfree: ¡Error! Arena esta en el tipo libre (free). Usa 'spawn1, spawn2, spawn3, etc' + statsfile: Error mientras se reconocia el archivo "stats" + teamnotfound: 'Equipo no encontrado: &a%1%&r' + uninstall: Error mientras se desinstalaba &a%1%&r + unknownmodule: 'Modulo (Module) no encontrado: %1%' + whitelist: + disallowed: No puedes %1% esto! [No estas en la Lista blanca (Whitelist)] + unknownsubcommand: 'Subcomando desconocido. Comandos Válidos: &a%1%&r' + unknowntype: 'Tipo desconocido. Tipos Válidos: &e%1%&r' + nopermto: + madmin: Administrar + create: Crear una Arena + disable: Deshabilitar + edit: Editar una Arena + enable: Habilitar + nopermjoin: Entrar a una Arena + reload: Recargar + remove: Remover una Arena + set: Establecer un Archivo de configuración + setup: Configurar una Arena + teleport: Teletransportarse a un lugar de aparición (Spawn) de alguna Arena + user: Usar PVP Arena + fight: + begins: Partida Comenzando... + draw: ¡EMPATE! ¡Ningún Ganador! + killedbyremaining: ¡%1% ha sido asesinado por %2%! Quedan %3% vidas. + killedbyremainingfrags: ¡%1% ha sido asesinado por %2%! Quedan %3% Vidas. + killedbyremainingteam: ¡%1% ha sido asesinado por %2%! Quedan %3% Vidas para %4%. + killedbyremainingteamfrags: ¡%1% ha sido asesinado por %2%! Quedan %3% Vidas para %4%. + killedby: '%1% ha sido asesinado por %2%!' + playerleft: ¡%1% se fue de la partida! + forcestop: Has forzado a que acabe la Arena. + gamemode: + free: Modo de juego &aLibre para todos (Free For All)&r establecido para la Arena &a%1%&r! + team: Modo de juego &aEquipos (Team)&r establecido para la Arena &a%1%&r! + general: + break: Romper (break) + place: Colocación (place) + use: Usar (use) + goal: + added: 'Meta (Goal) Añadida: &a%1%&r' + installing: 'Instala Metas (Goals) con el Comando: &a/pa install [Nombre de la + Meta (goalname)]&r' + removed: 'Meta removida: &a%1%&r' + blockdestroy: + typeset: 'Tipo de bloque establecido a: &e%1%' + setflag: 'Bloque establecido: %1%' + tosetflag: 'Bloque a establecer: %1%' + dom: + claiming: '&e¡Equipo %1% esta tomando una Bandera!' + claimed: '&e¡Equipo %1% ha tomado una Bandera!' + score: '&e¡Equipo %1% ha anotado %2% Puntos manteniendo una Bandera!' + unclaiming: '&e¡Una Bandera del Equipo %1% esta siendo tomada!' + unclaimingby: '&e¡Una Bandera del Equipo %1% esta siendo tomada por el Equipo + %2%!' + infected: + lost: '&6¡Los Jugadores Infectados han muerto!' + player: '&c¡%1% esta infectado!' + you: '&c¡Estas infectado D:!' + won: '&6¡Los Jugadores Infectados han ganado!' + killreward: + added: 'Recompensa de Asesinato añadida: &e%1%&r->&a%2%' + removed: 'Recompensa de Asesinato removida: &e%1%' + liberation: + liberated: ¡Equipo %1% ha sido liberado! + setbutton: 'Botón Añadido: %1%' + tosetbutton: 'Botón por añadir: %1%' + physicalflags: + holdflag: ¡Tienes que mantener la Bandera para poder llevarla devuelta! + sabotage: + tntignite: '%1% encendió la TNT del Equipo %2%!' + set: 'TNT añadida: %1%' + toset: 'TNT por añadir: %1%' + youtnt: '¡Estas llevando los materiales de Sabotage!' + tank: + tankdown: ¡El Tanque esta muerto! + tankmode: Todos a matar a %1% ¡Él/Ella es el Tanque! + tankwon: ¡El Tanque ha ganado! ¡Felicidades a %1%! + tdc: + denied: '%1% denied a kill!' + remaining: '%1% kills remaining for %2%.' + scored: '%1% scored a kill!' + youdenied: You denied a kill! + youscored: You scored a kill! + pillars: + msg: + block_broken: ¡[%1%] %2% rompió un Bloque! + lower: ¡[%1%] %2% acortó el Pilar! + block_placed: ¡[%1%] %2% puso un Bloque! + higher: ¡[%1%] %2% alargó el Pilar! + claimed: ¡[%1%] %2% ha tomado el pilar! + unclaimed: ¡[%1%] %2% esta siendo tomado! + score: '%1% hizo %2% punto/s' + help: + head: '&e--- &aAyuda de PVP Arena&e %1% &e---' + admin: '&c%1% - Ayuda de Administración' + setup: '&e%1% - Ayuda de Configuración' + custom: '&e%1% - Ayuda de Personalización' + game: '&a%1% - Ayuda dentro del Juego' + info: '&9%1% - Ayuda para obtener información' + import: + done: Arena satisfactoriamente importada &e%1%&r! + info: + classes: 'Clases: &a%1%&r' + goal_active: 'Meta(Goal): &a%1%&r' + goal_inactive: 'Meta(Goal): &b%1%&r &7== INACTIVA ==' + head_headlin: 'Información sobre Arena: &a%1%&r | [&a%2%&r]' + head_teams: 'Equipos: &a%1%&r' + mod_active: 'Modulos: &a%1%&r' + mod_inactive: 'Modulo: &b%1%&r &7== INACTIVE ==' + owner: 'Propietario: &a%1%&r' + regions: 'Regiones: &a%1%&r' + section: '----- &a%1%&r -----' + install: + installed: 'Instalado: &a%1%&r' + list: + arenas: 'Arenas Disponibles: %1%' + dead: 'Muerto: %1%' + fighting: 'En batalla: %1%' + lost: 'Perdido: %1%' + lounge: 'Sala de Espera (Lounge): %1%' + 'null': 'Glitched: %1%' + players: 'Jugadores: %1%' + team: 'Equipo %1%: %2%' + ready: 'Listo: %1%' + warm: 'Caliente: %1%' + watching: 'Observando: %1%' + log: + plugindisabled: Deshabilitado (version %1%) + pluginenabled: Habilitado (version %1%) + trickerdisabled: Plugin Seguimiento(Tracking) desabilitado. ¿Nos volveremos a ver? + trackingenabled: 'Plugin Segumieinto(Tracking) Habilitado. Establece el Segumiento(Tracking): + "False" dentro de la configuración principal para deshabilitarlo.' + updatedisabled: Actualizaciones deshabilitadas. Por favor mira dev.bukkit.org para Actualizaciones. + updateenabled: Comprobando Actualizaciones... + warning: '%1%' + messages: + toArena: Ahora estas hablando a la Arena! + toPublic: Ahora estas hablando publicamente! + toTeam: Ahora le estas hablando a tu Equipo! + general: '&e[%1%&e] &r%2%' + noplayer: Ningún Jugador en la Arena de PVP. + notice: + awarded: Se le ha otorgado %1% + nodropitem: ¡No tan Rápido! ¡No hagas trampas! + noteleport: Por favor usa '/pa leave' para salir de la Partida! + notice: 'Aviso: %1%' + playerawarded: '%1% se le ha otorgado %2%' + remove: '&cEsto removerá permanentemente la arena &a%1%&c. ¿Estás seguro? Entonces + usa el comando otra vez!&r Para deshabilitar este mensaje, busca ''safeadmin'' + en tu config.yml' + waitingequal: Espera por un equipo con un número igual de jugadores! + waitingforarena: Esperando por una arena en juego para terminar! + welcomespec: Bienvenio al área de espectador! + gameloot: Aquí está tu botín! + welcomespec2: /pa bet [name] [monto] para apostar a un equipo o jugador + youdeath: Has entrado a una Región de MUERTE. Adiós! + youescaped: Te saliste de la Región de Batalla. Adiós! + youleft: Saliste de la Arena + younocamp: Estas en una Región de No Campeo. ¡Muevete! + playerhaswon: '%1% es el ganador!' + playerready: '%1%&e esta listo!' + notreadyplayers: Algunos jugadores no estan listos + players: Jugadores + ready: + list: 'Jugadores: %1%' + done: Te has marcado como listo + region: + flag: + added: 'Región flag añadida: &a%1%&r' + removed: 'Región flag removida: &a%1%&r' + height: 'Altura de Región puesta a: &a%1%&r' + pos1: Primer punto puesto. + pos2: Segundo punto puesto. + protection_added: 'RegionProtection añadida: &a%1%&r' + protection_removed: 'RegionProtection removida: &a%1%&r' + radius: 'Radio de Región puesta a: &a%1%&r' + removed: 'Región removida: %1%' + saved: Región guardada. + saved_notice: '&cHas creado una Región &oCUSTOM&c. No tiene función aún, conviertela + a una Región de Batalla con el comando &r/pvparena %1% !rt %2% BATTLE' + select: Selecciona 2 puntos, Click Izquierdo y luego Click Derecho + setting: Configuración de Región activada. + typeset: 'Tipo de Región puesta: &e%1%' + youselect: Has activado la selección de Región para la Arena &a%1%&r! + regions: + flags: 'Región Flags: &a%1%&r' + head: '--- &aRegiones de Arena&r [&e%1%&r]---' + listhead: '--- &aRegiones de Arena&r [&e%1%&r]---' + listvalue: '&a%1%&r: %2%, %3%' + protections: 'Región Protections: &a%1%&r' + shape: 'Forma de Región: &a%1%&r' + type: 'Tipo de Región: &a%1%&r' + reloaded: ¡Configuración recargada! + round: + display: 'Ronda #%1%: %2%' + added: 'Meta(Goal) añadida para Ronda: &e%1%' + removed: 'Meta(Goal) removida para Ronda: &e%1%' + set: + done: '&a%1%&r puesto a &e%2%&r!' + help: use /pa {NombreDeLaArena} set [pagina] para obtener una lista de nodos + unknown: 'Nodo desconocido: &e%1%&r!' + setowner: + done: '&a%1%&r ahora es el dueño de la Arena &a%2%&r!' + spawn: + freelounge: Sala de Espera(Lounge) ajustada + teamlounge: 'Sala de Espera(Lounge) para el Equipo: %1% puesta' + notset: 'Lugar de Reaparición(Spawn) no ajustado: &a%1%&r' + removed: 'Lugar de Reaparición(Spawn) removido: &a%1%&r' + set: 'Lugar de Reaparición(Spawn) ajustado: &a%1%&r' + setdone: 'Lugar de Reaparición(Spawn) ajuste hecho: &a%1%&r' + setstart: 'Lugar de Reaparición(Spawn) ajustes comenzados: &a%1%&r' + stats: + filedone: Archivo de estdística cargado! + head: TOP de Estadísticas %1% (%2%) + typenotfound: 'Tipo de estadística no encontrado, valores válidos: &e%1%&r' + stattype: + DAMAGE: Daño completo tratado + DAMAGETAKE: Daño completo tomado + DEATHS: muertes + KILLS: matanzas + LOSSES: partidas perdidos + MAXDAMAGE: máximo de daño dado + MAXDAMAGETAKE: máximo daño tomado + 'NULL': nombre de jugador + WINS: partidas ganados + team: + haswon: Equipo %1%&r son los ganadores! + ready: Equipo %1%&r está listo! + teams: + list: 'Equipos disponibles: %1%' + add: 'Equipo agregado: %1%' + set: 'Equipo puesto: %1%' + remove: 'Equipo removido: %1%' + template: + loaddone: Plantilla cargada desde &a%1%&r + savedone: Plantilla guardada en &a%1%&r + time: + minutes: minutos + seconds: segundos + timer: + countdowninterrupt: Cuenta regresiva interrumpida! Pulse el bloque listo! + ending: El partido terminará en %1%! + resetting: La arena se restaurará en %1%! + starting: Comenzando en %1%! + warmingup: Warming up... %1%! + pvpactivating: PVP será activado en %1%! + walls: Las paredes serán removidas en %1%! + togglemod: + notice: '&cHas activado un modulo que requiere BATTLE región! Type &r/pvparena + [arena] !rt [región] BATTLE' + uninstall: + done: 'desinstalar: &a%1%&r' + whitelist: + added: Agregar &a%1%&r a &e%2%&r whitelist! + allcleared: Toda la whitelist vaciada! + cleared: Whitelist &e%1%&r vaciada! + help: 'Usage: blacklist borrada | blacklist [tipo] [vacir|agregar|remover] [id]' + removed: Removido &a%1%&r de &e%2%&r whitelist! + show: 'Whitelist &e%1%&r:' + mod: + aftermatch: + aftermatch: El aftermatch ha comenzado! + startingin: AfterMatch en %1%! + spawnnotset: Lugar de Reaparición(Spawn) 'after' no establecido! + announcements: + ignoreon: Ahora estás ignorando anuncios! + ignoreoff: Ahora estás recibiendo anuncios! + arenaboards: + createarenaboard: Crea una ArenaBoard + arenaboarddestroyed: ArenaBoard destruida! + boardexists: ArenaBoard ya existe!' + sortingby: ArenaBoard ahora clasificado por %1% + autovote: + arenarunning: 'Arena en juego: %1%' + autojoin: Arena auto join comenzó! + playervoted: '%2% Vota por arena %1%!' + youvoted: Has votado por la Arena %1%! + duel: + accepted: '%1% &eacepta el desafío! El juego está comenzando.' + announce: '%1% &eTe ha desafiado! Acepta el duelo con &r/pa %2% accept.' + requested: Has &edesafiado &r%1%&e! + starting: El duelo comienza! + fixinventorylos: + gamemode: Entre en el modo survival antes de unirse! + invenory: Vacíe su inventario antes de unirse! + latelounge: + llannounce: Arena %1% está comenzando! Jugador %2% desea comenzar. Únase con /pa %1% + llposition: Usted está en la cola %1%! + llrejoin: La verificación se ha cortado, no será capaz de unirse. Vuelva a unirse cuando pueda! + llwait: Arena comenzará pronto, por favor espere! + playerfinder: + near: 'Jugador más cercano: %1% bloques!' + point: Brújula que señala al jugador más cercano! + powerups: + invalidpowerupeffect: 'PowerupEffect Inválido: %1%' + puplayer: '%1% ha recogido PowerUp %2%!' + puserver: PowerUp desplegado! + skins: + dc: Conexión dentro de DisguiseCraft! + md: Conexión dentro de MobDisguise! + nomod: Ningún plugin de ocultamieto encontrado, Módulo de Skins está inactivo! + showclass: Clase &e%1%&r será ocultado a &a%2% + showteam: Equipo %1% será ocultado a %2% + specialjoin: + done: Bloque con el cuál los jugadores podrán unirse a la partida puesto en - %1% + start: Poniendo un Bloque de poder unirse + stop: Bloque de poner unirse selección abortada + startfreeze: + announce: La Partida comenzará en %1% segundos + tempperms: + noperms: Plugin de Permisos no encontrado, predeterminando a OP. + head: 'Permiso temporal de &e%1%&r:' + added: Permiso temporal &e%1%&r Agregado a &a%2%&r + removed: Permiso temporal &e%1%&r Removido de &a%2%&r + vault: + 'on': <3 eConomy + 'off': &a%2%' + removed: 'Mise à prix supprimée: &e%1%' + liberation: + liberated: L'équipe %1% a été libérée ! + setbutton: 'Bouton configuré: %1%' + scoreboardheading: 'Players in jail:' + scoreboardseparator: '----------------' + tosetbutton: 'Bouton à configurer: %1%' + physicalflags: + holdflag: Vous avez pris le drapeau, rapportez le ! + sabotage: + tntignite: '%1% a allumé la TNT de l''équipe %2% !' + set: 'TNT configurée: %1%' + toset: 'TNT a configurer: %1%' + noselfdestroy: 'Vous ne pouvez pas faire exploser votre TNT!' + youtnt: 'Vous portez maintenant l''outil de sabotage !' + notgooditem: 'Vous avez besoin de l''outil de sabotage pour allumer la TNT.' + tank: + tankdown: Le tank est H.S. ! + tankmode: MODE TANK ! Tous le monde doit tuer %1%, le tank ! + tankwon: Le tank a gagné ! Félicitations à %1% ! + tdc: + denied: '%1% a refusé un kill!' + remaining: '%1% kills restants pour %2%.' + scored: '%1% a enregistré un kill!' + youdenied: Vous avez refusé un kill ! + youscored: Vous avez enregistré un kill ! + pillars: + msg: + block_broken: '[%1%] %2% a cassé un bloc !' + lower: '[%1%] %2% a raccourci la colonne!' + block_placed: '[%1%] %2% a posé un bloc !' + higher: '[%1%] %2% a agrandi la colonne !' + claimed: '[%1%] %2% a réclamé la colonne !' + unclaimed: '[%1%] %2% a libéré la colonne !' + score: '%1% a marqué %2% points' + help: + head: '&e--- &aAide de PVP Arena&e %1% &e---' + admin: '&c%1% - aide administration' + setup: '&e%1% - aide configuration' + custom: '&e%1% - aide customisation' + game: '&a%1% - aide en jeu' + info: '&9%1% - Obtenir des informations' + import: + done: L'arène &e%1%&r a été imortée avec succès ! + info: + classes: 'Classes: &a%1%&r' + goal_active: 'Objectif: &a%1%&r' + goal_inactive: 'Objectif: &b%1%&r &7== INACTIF ==' + head_headlin: 'Infos arène à propos de: &a%1%&r | [&a%2%&r]' + head_teams: 'Equipes: &a%1%&r' + mod_active: 'Module: &a%1%&r' + mod_inactive: 'Module: &b%1%&r &7== INACTIF ==' + owner: 'Propriétaire: &a%1%&r' + regions: 'Regions: &a%1%&r' + section: '----- &a%1%&r -----' + install: + installed: 'installé: &a%1%&r' + list: + arenas: 'Arènes disponibles: %1%' + dead: 'Mort: %1%' + fighting: 'Combat: %1%' + lost: 'Perdu: %1%' + lounge: 'Lounge: %1%' + 'null': 'Bugué: %1%' + players: 'Joueurs: %1%' + team: 'Equipe %1%: %2%' + ready: 'Prêt: %1%' + warm: 'Chaud: %1%' + watching: 'Observation: %1%' + log: + plugindisabled: désactivé (version %1%) + pluginenabled: activé (version %1%) + trickerdisabled: Suivi du plugin désactivé. Rendez-vous bientôt ? + trackingenabled: 'Suivi du plugin activé. Configurer le suivi: false dans la configuration + pricipale à désactiver.' + updatedisabled: Mises à jour désactivée. Pensez à vérifier spigot.org pour les mises à jour. + updateenabled: Recherche de mise à jour... + warning: '%1%' + messages: + toArena: Vous parlez maintenant dans l'arène ! + toPublic: Vous parlez maintenant au public ! + toTeam: Vous parlez maintenant à votre équipe ! + general: '&e[%1%&e] &f%2%' + noplayer: Aucun joueur dans l'arène PVP. + notice: + awarded: Vous avez été décerné %1% + nodropitem: Pas si vite ! On ne triche pas ! + noteleport: Merci d'utiliser '/pa leave' pour quitter le combat ! + notice: 'Notice: %1%' + playerawarded: '%1% a été décerné %2%' + remove: '&cCeci va définitivement supprimer l''arène &a%1%&c. Etes-vous sûr ? + Si oui retapez la commande !&f Pour désactiver ce message, allez dans ''safeadmin'' + de votre fichier config.yml' + waitingequal: En attente d'un équilibre du nombre de joueurs dans les équipes + ! + waitingforarena: En attente d'un arène en cours pour terminer ! + welcomespec: Bienvenue dans la zone des spectateurs ! Tape '/pa leave' pour la + quitter. + gameloot: Voici votre butin de jeu ! + welcomespec2: /pa bet [name] [amount] pour parier sur un équipe ou un joueur. + youdeath: Vous entrez dans une zone de MORT. Au revoir ! + youescaped: Vous sortez de la zone de combat. Au revoir ! + youleft: Vous venez de quitter l'arène ! + younocamp: Vous êtes dans une zone de MOUVEMENT. Déplacez-vous! + playerhaswon: '%1% est le champion !' + playerready: '%1%&e est prêt !' + player: + prevented: + break: '&cVous n''êtes pas autorisé à casser des blocs !' + place: '&cVous n''êtes pas autorisé à poser des blocs !' + tnt: '&cVous n''êtes pas autorisé à utiliser de la TNT !' + tntbreak: '&cVous n''êtes pas autorisé à casser de la TNT !' + drop: '&cVous n''êtes pas autorisé jeter vos items !' + inventory: '&cVous n''êtes pas autorisé à accéder à cela !' + craft: '&cVous n''êtes pas autorisé à crafter !' + notreadyplayers: Les joueurs ne sont pas prêts + players: Joueurs + ready: + list: 'Joueurs: %1%' + done: Tu viens d'être enregistré comme prêt ! + region: + clear: + added: 'Région ajoutée à la whitelist de nettoyage des entités: &a%1%&r' + list: 'Liste des régions appartenant à la whitelist de nettoyage des entités: &a%1%&r' + removed: 'Région retirée de la whitelist de nettoyage des entités: &a%1%&r' + flag: + added: 'Flag ajouté: &a%1%&r' + removed: 'Flag suppimé: &a%1%&r' + height: 'Hauteur de région: &a%1%&r' + pos1: Premier point selectionné. + pos2: Second point selectionné. + protection_added: 'Protection ajoutée: &a%1%&r' + protection_removed: 'Protection supprimée: &a%1%&r' + radius: 'Rayon de la région: &a%1%&r' + removed: 'Region supprimée: %1%' + saved: Region enregistrée. + saved_notice: '&6Vous avez créé une région &oCUSTOM&6. Celle-ci n''a aucune fonction. Pour créer une région + pour combattre, tapez &r/pvparena %1% !rt %2% BATTLE' + select: Selectionne deux points avec le wand item, clic gauche pour le prmier + et clic droit pour le second ! + setting: Paramètrage de région activé. + typeset: 'Type de région modifié en: &e%1%' + youselect: Vous séléctionnez maintenant une région pour &a%1%&r! + regions: + flags: 'Flags de région: &a%1%&r' + head: '--- &aRégion de l''arène&r [&e%1%&r]---' + listhead: '--- &aRégions de l''arène&r [&e%1%&r]---' + listvalue: '&a%1%&r: %2%, %3%' + protections: 'Region Protections: &a%1%&r' + shape: 'Forme de la région: &a%1%&r' + type: 'Type de région: &a%1%&r' + reloaded: Config actualisée! + ymls: + reloaded: Fichiers de langue rechargés ! + round: + display: 'Round #%1%: %2%' + added: 'Objectif ajouté au round: &e%1%' + removed: 'Objectif supprimé du round: &e%1%' + roundsdisplay: Round %1% / %2% + roundsdisplayseparator: '-----------' + set: + items_not: Veuillez utiliser les mots clés "hand" ou "inventory" pour définir un item dans la configuration. + done: '&a%1%&r configuré à &e%2%&r!' + help: utilise /pa {arenaname} set [page] pour obtenir la liste des configurations + unknown: 'Config inconnue: &e%1%&r!' + setowner: + done: '&a%1%&r est maintenant propritétaire de l''arène &a%2%&r!' + spawn: + freelounge: Lounge configuré + teamlounge: 'Lounge configuré: %1%' + notset: 'Spawn non configuré: &a%1%&r' + offset: Spawn &a%1%&r offset by &a%2%&r blocks. + removed: 'Spawn supprimé: &a%1%&r' + set: 'Spawn configuré: &a%1%&r' + setdone: 'Paramètrage du spawn terminé: &a%1%&r' + setstart: 'Paramètrage du spawn: &a%1%&r' + unknown: 'Spawn inconnu : &a%1%&r' + stats: + filedone: Fichier stats chargé ! + head: Statistiques TOP %1% (%2%) + typenotfound: 'Type de statistique non trouvé! Valeurs correctes: &e%1%&r' + stattype: + DAMAGE: dommages totaux accordé + DAMAGETAKE: dommages totaux subis + DEATHS: morts + KILLS: tués + LOSSES: matchs perdus + MAXDAMAGE: domages maximums accordés + MAXDAMAGETAKE: Dommages maximums subis + 'NULL': nom du joueur + WINS: matchs gagnés + team: + haswon: L'équipe %1% gagne la partie ! + ready: L'équipe %1% est prête ! + teams: + list: 'Equipes disponibles: %1%' + add: 'Equipe ajoutée: %1%' + set: 'Equipe modifiée: %1%' + remove: 'Equipe suppriméé: %1%' + template: + loaddone: Template loaded from &a%1%&r + savedone: Template saved to &a%1%&r + time: + minutes: minutes + seconds: secondes + timer: + countdowninterrupt: Compte à rebours interrompu ! Frappe le bloc de départ ! + ending: Le match se termine dans %1% ! + resetting: L'arène sera réinitialisée dans %1% ! + starting: Début dans %1%! + warmingup: Echauffement... %1%! + pvpactivating: Le PVP sera activé dans %1%! + walls: Les murs disparaitront dans %1%! + togglemod: + notice: '&cVous venez d''activer un module nécessitant une région de type BATTLE ! Pour changer le type de région + Tapez &r/pvparena [arena] !rt [region] BATTLE' + uninstall: + done: 'supprimé: &a%1%&r' + whitelist: + added: .&a%1%&r ajouté à la whitelist &e%2%&r ! + allcleared: Toutes les whitelistes ont été effacées ! + cleared: Whitelist &e%1%&r effacée ! + help: 'Utilisation: blacklist clear | blacklist [type] [clear|add|remove] [id]' + removed: .&a%1%&r supprimé de la whiteliste &e%2%&r ! + show: 'Whitelist &e%1%&r:' + mod: + aftermatch: + aftermatch: L'aprèsmatch a commencé ! + startingin: AprèsMatch dans %1%! + spawnnotset: Spawn 'after' non configuré ! + announcements: + ignoreon: Vous ignorez maintenant les annonces ! + ignoreoff: Vous recevrez maintenant les annonces ! + arenaboards: + createarenaboard: créer un tableau des scores + arenaboarddestroyed: tableau des scores détruit ! + boardexists: Le tableau des scores existe déjà !' + sortingby: Tableau des scores maintenant trié par %1% + autovote: + arenarunning: 'Arène en cours: %1%' + autojoin: Arena auto join démarré ! + playervoted: '%2% a voté pour l''arène %1%!' + youvoted: Vous avez voté pour l'arène %1% ! + duel: + accepted: '%1% &ea accepté le challenge ! Que le jeu commence !' + announce: '%1% &evous a defié! Accepte le duel avec &f/pa %2% accept.' + announcemoney: '&eLe prix d''entrée est de &c%1%&e!' + announce2: '&eRefusez le duel avec &r/pa %2% decline&e.' + cancelled: '&cLe duel a été annulé!' + busy: '%1% &ecombat actuellement. Veuillez réessayer plus tard.' + declineds: Votre opposant a refusé. Le duel est annulé. + declinedr: Vous avez refusé le duel ! + requested: Vous &eavez défié &f%1%&e! + requestedalready: Vous avez déjà défié quelqu'un ! + requestexpireds: Votre opposant n'a pas accepté le duel a temps. Le duel est donc annulé. + requestexpiredr: Vous n'avez pas accepté le duel a temps. Le duel est donc annulé. + starting: Le duel commence ! + nodirectjoin: 'Vous pouvez rejoindre directement le combat ! Utilisez: &e/pa %1% duel [nomDuJoueur]' + fixinventorylos: + gamemode: Passez en mode survie avant de rejoindre l'arène ! + invenory: Videz votre inventaire avant de rejoindre l'arène ! + latelounge: + llannounce: L'arène %1% est ouverte ! Le joueur %2% veut commencer. Rejoint + le avec /pa %1% + llposition: Vous attendez à la position numéro %1%! + llrejoin: Vous n'êtes pas en mesure de rejoindre les joueurs prêts. Rejoignez-les + quand vous pouvez ! + llwait: L'arène va ouvrir prochainement, veuillez être patient ! + llleave: Vous venez de quitter la file d'attente de l'arène %1%. + playerfinder: + near: 'Joueur le plus proche: %1% blocs!' + point: La boussole indique le joueur le plus proche ! + powerups: + invalidpowerupeffect: 'PowerupEffect invalide: %1%' + puplayer: '%1% a collecté le PowerUp %2%!' + puserver: PowerUp déployé! + respawnrelay: + respawning: Réapparition dans %1%! + skins: + dc: Connecté à DisguiseCraft ! + ld: Hooking into LibsDisguises! + nomod: Aucun plugin de déguisement trouvé, désactivation du module de skins + ! + showclass: La classe &e%1%&r wsera déguisée en &a%2% + showteam: L'équipe %1% sera déguisée en %2% + md: Connecté à MobDisguise ! + specialjoin: + done: Le join block est configuré - %1% + start: Configuration du join block ! + stop: Annulation de la selection du join block! + squads: + nosquad: 'Aucune escouade n''est chargée. Ajoutez-en avec la commande /pa [arena] !sq add [name]' + listhead: Liste des escoudes de l'arène &b%1% + listitem: 'Escouade %1% (max: %2%) %3%' + added: L'escouade %1% a été ajoutée + set: L'escouade %1% a été modifiée + removed: L'escouade %1% a été supprimée + notexist: L'escouade %1% n'existe pas + error: Erreur lors de l'édition des escouades, la syntaxe de la command est incorrecte ! + full: L'escouade est pleine ! + help: |- + /pa !sq | affiche la liste des escouades de l'arène + /pa !sq add [name] [limit] | ajoute une escoude avec une limite (mettre 0 pour ne pas avoir de limite) + /pa !sq set [name] [limit] | modifier la limite de joueurs d'une escouade + /pa !sq remove [name] | supprimer une escouade + startfreeze: + announce: Le jeu commencera dans %1% secondes ! + tempperms: + noperms: Plugin de permission non trouvé, par défaut OP. + head: 'Permission temporaire de &e%1%&r:' + added: Permission temporaires &e%1%&r ajoutée à &a%2%&r + removed: Permission temporaire &e%1%&r supprimée à &a%2%&r + vault: + 'on': <3 eConomy + 'off': &a%2%' + removed: 'Ðаграда за убийÑтво удалена: &e%1%' + liberation: + liberated: Команда %1% была оÑвобождена! + setbutton: 'Кнопка выбрана: %1%' + tosetbutton: 'Кнопка Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð°: %1%' + physicalflags: + holdflag: Ð’Ñ‹ захватили флаг, верните его к Ñебе на базу! + sabotage: + tntignite: '%1% подожгли TNT команды %2%!' + set: 'TNT выбрана: %1%' + toset: 'TNT Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð°: %1%' + youtnt: 'У Ð²Ð°Ñ ÐµÑÑ‚ÑŒ TNT Ð´Ð»Ñ Ñабботажа!' + tank: + tankdown: Танк убит! + tankmode: Режим танка! Ð’Ñе должны убить %1%, он танк! + tankwon: Танк победил! ПоздравлÑем %1%! + pillars: + msg: + block_broken: '[%1%] %2% Ñломал блок!' + lower: '[%1%] %2% укоротил колонну!' + block_placed: '[%1%] %2% поÑтавил блок!' + higher: '[%1%] %2% удлинил колону!' + claimed: '[%1%] %2% захватил колонну!' + unclaimed: '[%1%] %2% перехватил колонну!' + score: '%1% получают %2% очков' + help: + head: '&e--- &aPVP Arena помощь&e %1% &e---' + admin: '&c%1% - помощь админиÑтрации' + setup: '&e%1% - помощь в Ñоздании' + custom: '&e%1% - помощь в наÑтройке' + game: '&a%1% - помощь в игре' + info: '&9%1% - помощь в получении информации' + import: + done: Удачный импорт арены &e%1%&r! + info: + classes: 'клаÑÑÑ‹: &a%1%&r' + goal_active: 'Цель: &a%1%&r' + goal_inactive: 'Цель: &b%1%&r &7== Ð½ÐµÐ°ÐºÑ‚Ð¸Ð²Ð½Ð°Ñ ==' + head_headlin: 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± арене: &a%1%&r | [&a%2%&r]' + head_teams: 'Команды: &a%1%&r' + mod_active: 'Модули: &a%1%&r' + mod_inactive: 'Модули: &b%1%&r &7== Ð½ÐµÐ°ÐºÑ‚Ð¸Ð²Ð½Ð°Ñ ==' + owner: 'Владельцы: &a%1%&r' + regions: 'Регионы: &a%1%&r' + section: '----- &a%1%&r -----' + install: + installed: 'уÑтановлены: &a%1%&r' + list: + arenas: 'ДоÑтупные арены: %1%' + dead: 'Мёртвые: %1%' + fighting: 'СражающиеÑÑ: %1%' + lost: 'ПотерÑнные: %1%' + lounge: 'Лобби: %1%' + 'null': 'ЗавиÑшие: %1%' + players: 'Игроки: %1%' + team: 'Команды %1%: %2%' + ready: 'Готовы: %1%' + warm: 'Ожидающие: %1%' + watching: 'Зрители: %1%' + log: + plugindisabled: выключен (верÑÐ¸Ñ %1%) + pluginenabled: включён (верÑÐ¸Ñ %1%) + trickerdisabled: ДиагноÑтика плагина выключена. УвидимÑÑ Ð¿Ð¾Ð·Ð¶Ðµ? + trackingenabled: 'ДиагноÑтика плагина включена. Выбор диагноÑтики: false в главном файле конфигурации Ð´Ð»Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ.' + updatedisabled: Обновление выключено. ПожалуйÑта проверьте dev.bukkit Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ. + updateenabled: Проверка на наличие обновлений... + warning: '%1%' + messages: + toArena: Теперь вы говорите внутри арены! + toPublic: Теперь вы говорите Ñо вÑеми! + toTeam: Теперь вы разговариваете Ñ Ð²Ð°ÑˆÐµÐ¹ командой! + noplayer: Ðет игроков в PVP arena. + notice: + awarded: Ð’Ñ‹ были награждены %1% + nodropitem: Ðе так быÑтро! Ðе читерить! + noteleport: ПожалуйÑта иÑпользуйте '/pa leave' Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð° из игры! + notice: 'Внимание: %1%' + playerawarded: '%1% был награждён %2%' + remove: '&cЭто навÑегда удалит вашу арену &a%1%&c. Ð’Ñ‹ уверены? Тогда + введите команду ещё раз!&f Чтобы выключить Ñто Ñообщение, поÑмотрите ''safeadmin'' в вашем + config.yml' + waitingequal: Ждём пока в командах будет минимальное чиÑло игроков! + waitingforarena: Ожидайте, пока игра завершитÑÑ! + welcomespec: Добро пожаловать в зал зрителей! + welcomespec2: /pa bet [имÑ] [цена] Ñделать Ñтавку на игрока или команду! + youdeath: Ð’Ñ‹ вошли в регион Ñмерти. Пока ;)! + youescaped: Ð’Ñ‹ ушли Ñ Ð¿Ð¾Ð»Ñ Ð±Ð¾Ñ. Пока ;)! + youleft: Ð’Ñ‹ вышли из игры! + younocamp: Ð’Ñ‹ в некемперÑком регионе. ДвигайтеÑÑŒ! + playerhaswon: '%1% победитель!' + playerready: '%1%&e готов!' + notreadyplayers: Игроки не готовы + players: Игроки + ready: + list: 'Игроки: %1%' + done: Ð’Ñ‹ уже готовы! + region: + flag: + added: 'Флаг региона добавлен: &a%1%&r' + removed: 'Флаг региона удалён: &a%1%&r' + height: 'Ð’Ñ‹Ñота региона уÑтановлена на: &a%1%&r' + pos1: ÐŸÐµÑ€Ð²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° выбрана. + pos2: Ð’Ñ‚Ð¾Ñ€Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° выбрана. + protection_added: 'Защита региона Ñоздана: &a%1%&r' + protection_removed: 'Защита региона удалена: &a%1%&r' + radius: 'Ð Ð°Ð´Ð¸ÑƒÑ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð°: &a%1%&r' + removed: 'Регион удалён: %1%' + saved: Регион Ñохранён. + select: Выбирете 2 точки палочкой, Ñначала левой кнопкой мышки и потом правой! + setting: ÐайÑтройка региона включена. + typeset: 'Тип региона выбран: &e%1%' + youselect: Теперь вы выбираете регион Ð´Ð»Ñ ÐºÐ°Ñ€Ñ‚Ñ‹ &a%1%&r! + regions: + flags: 'Флаги региона: &a%1%&r' + head: '--- &aРегион арены&r [&e%1%&r]---' + listhead: '--- &aРегионы арены&r [&e%1%&r]---' + listvalue: '&a%1%&r: %2%, %3%' + protections: 'Защиты региона: &a%1%&r' + shape: 'Форма региона: &a%1%&r' + type: 'Тип региона: &a%1%&r' + reloaded: ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð°! + round: + display: 'Раунд #%1%/%2%' + added: 'Добавлена цель раунда: &e%1%' + removed: 'Удалена цель раунда: &e%1%' + set: + done: '&a%1%&r set to &e%2%&r!' + help: ИÑпользуйте /pa {arenaname} set [Ñтраница] Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ðµ инÑтрукций + unknown: 'ÐеизеÑÑ‚Ð½Ð°Ñ Ñтраница: &e%1%&r!' + setowner: + done: '&a%1%&r теперь владелец арены &a%2%&r!' + spawn: + freelounge: Лобби выÑтавлено + teamlounge: 'Лобби выÑтавлено: %1%' + notset: 'Точка Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½Ðµ указана: &a%1%&r' + removed: 'Точка Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð°: &a%1%&r' + set: 'Точка Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð°: &a%1%&r' + setdone: 'Точка Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ ÑƒÐ´Ð°Ñ‡Ð½Ð¾ выÑтавлена: &a%1%&r' + setstart: 'ÐаÑтройка точки Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½Ð°Ñ‡Ð°Ñ‚Ð°: &a%1%&r' + stats: + filedone: Файл Ñтатичтики загружен! + head: СтатиÑтика ТОП %1% (%2%) + typenotfound: 'Тип ÑтатиÑтики не найден! ДоÑтупные значениÑ: &e%1%&r' + stattype: + DAMAGE: полный наноÑимый урон + DAMAGETAKE: полный забираемый урон + DEATHS: Ñмерти + KILLS: убийÑтва + LOSSES: матчей проиграно + MAXDAMAGE: макÑимальный урон + MAXDAMAGETAKE: макÑимальный нанеÑённый урон + 'NULL': Ð¸Ð¼Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ° + WINS: матчей выиграно + team: + haswon: '%1% Чемпионы!' + ready: '%1% готовы!' + teams: + list: 'ДоÑтупные команды: %1%' + add: 'Команда Ñоздана: %1%' + set: 'Команда выбрана: %1%' + remove: 'Команда удалена: %1%' + time: + minutes: минут + seconds: Ñекунд + timer: + countdowninterrupt: Таймер interrupted! Ударьте железный блок Ð´Ð»Ñ Ð³Ð¾Ñ‚Ð¾Ð²Ð½Ð¾Ñти! + ending: Матч закончитÑÑ Ñ‡ÐµÑ€ÐµÐ· %1%! + resetting: Ðрена будет перезапущена через %1%! + starting: Ðачало через %1%! + warmingup: Warming up... %1%! + pvpactivating: ПвП будет включен через %1%! + walls: Стены будут убраны через %1%! + uninstall: + done: 'Удалено: &a%1%&r' + whitelist: + added: Добавление &a%1%&r в &e%2%&r вайтлиÑÑ‚! + allcleared: Ð’Ñе вайтлиÑÑ‚Ñ‹ очищены! + cleared: ВайтлиÑÑ‚ &e%1%&r очищен! + help: 'ИÑпользуйте: blacklist clear | blacklist [type] [clear|add|remove] [id]' + removed: Removed &a%1%&r from &e%2%&r whitelist! + show: 'Whitelist &e%1%&r:' + mod: + aftermatch: + aftermatch: AfterMatch начинаетÑÑ! + startingin: AfterMatch через %1%! + spawnnotset: Точка Ð²Ð¾Ð·Ñ€Ð°Ð¶Ð´ÐµÐ½Ð¸Ñ 'after' не уÑтановлена! + announcements: + ignoreon: Теперь вы игнорируете оповещениÑ! + ignoreoff: Теперь вы получаете оповещениÑ! + arenaboards: + createarenaboard: Ñоздать Границу Ðрены + arenaboarddestroyed: Граница арены уничтожена! + boardexists: Граница арены Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует!' + sortingby: Граница арены теперь ÑортируетÑÑ Ñ‡ÐµÑ€ÐµÐ· %1% + autovote: + arenarunning: 'Игра запущена: %1%' + autojoin: Ðвто приÑоединение к игре началоÑÑŒ! + playervoted: '%2% проголоÑовал за %1%!' + youvoted: Ð’Ñ‹ проголоÑовали за %1%! + duel: + accepted: '%1% &eÑоглаÑилÑÑ Ð½Ð° дуель! Дуедь начинаетÑÑ.' + announce: '%1% &eвызывает Ð²Ð°Ñ Ð½Ð° дуель! ПринÑÑ‚ÑŒ вызов &f/pa %2% accept.' + starting: Дуель начинаетÑÑ! + fixinventorylos: + gamemode: Смена игрового режима перед приÑоединением! + invenory: ОчиÑтка Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ð¿ÐµÑ€ÐµÐ´ приÑоединением! + latelounge: + llannounce: Игра на карте %1% начинаетÑÑ! Игроков,которые хотÑÑ‚ начат играть %2%. ПриÑоединитьÑÑ /pa %1% + llposition: Ваше меÑто в очереди %1%! + llrejoin: Проверка готовноÑти говорит,что вы не Ñмогли подключитÑÑ Ðº игре. ПереподÑоединитеÑÑŒ, когда Ñможете! + llwait: Игра Ñкоро начнётÑÑ, пожалуйÑта подождите! + playerfinder: + near: 'Ближайщий игрок от Ð²Ð°Ñ Ð² %1% блоках!' + point: ÐšÐ¾Ð¼Ð¿Ð°Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ позицию ближайшего игрока! + powerups: + invalidpowerupeffect: 'Ðеверный Ñффект повышениÑ: %1%' + puplayer: '%1% доÑтиг Ð¿Ð¾Ð²Ñ‹ÑˆÐµÐ½Ð¸Ñ %2%!' + puserver: Понижение! + skins: + dc: Подключение в DisguiseCraft! + md: Подключение в MobDisguise! + nomod: Ðе найден плагин превращений, модуль Ñкинов выключен! + showclass: КлаÑÑ &e%1%&r будет превращён в &a%2% + showteam: Команда %1% будет превращёна в %2% + specialjoin: + done: Блок готовноÑти выбран тут - %1% + start: Выбор блока готовноÑти! + stop: Отмена Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ð½Ð° блок готовноÑти! + startfreeze: + announce: Игра начнётÑÑ Ñ‡ÐµÑ€ÐµÐ· %1% Ñекунд! + tempperms: + noperms: Плагин прав не найден, по умалчанию доÑтупно оперторам. + head: 'Временные права Ð´Ð»Ñ &e%1%&r:' + added: Временные права &e%1%&r Ñделаны Ð´Ð»Ñ &a%2%&r + removed: Временные права &e%1%&r удалены у &a%2%&r + vault: + 'on': <3 eConomy + 'off': - 4.0.0 - - net.slipcor - pvparena - 1.3.4-SNAPSHOT - PVP Arena - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/groups/public/ - - - - - - org.bukkit - bukkit - 1.11.2-R0.1-SNAPSHOT - jar - provided - - - - http://pa.slipcor.net - - jenkins - https://ci2.craftyn.com - - - - clean package install - pvparena - ${basedir}/src - - - - . - true - ${basedir}/src - - config.yml - plugin.yml - - - - . - true - ${basedir} - - README.creole - READMEv01.creole - READMEv010.creole - READMEv02.creole - READMEv03.creole - READMEv04.creole - READMEv05.creole - READMEv06.creole - READMEv07.creole - READMEv08.creole - READMEv09.creole - READMEv10.creole - SETUP.creole - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - UTF-8 - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.3.2 - - - - com.google.code.maven-replacer-plugin - maven-replacer-plugin - 1.3.8 - - - prepare-package - - replace - - - - - target/classes/plugin.yml - - - jenkins-build-number - ${BUILD_NUMBER} - - - - - - + + 4.0.0 + + net.slipcor + pvparena + 1.15.2-SNAPSHOT + PVP Arena + https://github.com/Eredrim/pvparena + + + + UTF-8 + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + CodeMC + https://repo.codemc.org/repository/maven-public/ + + + + + + org.spigotmc + spigot-api + 1.13.2-R0.1-SNAPSHOT + jar + provided + + + org.bstats + bstats-bukkit + 1.7 + compile + + + + + clean package install + pvparena-${project.version}${buildVersion} + ${basedir}/src + + + + . + true + ${basedir}/src + + config.yml + plugin.yml + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + UTF-8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + + org.bstats + net.slipcor.pvparena + + + + + + package + + shade + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md index 57be5ed8a..235941f79 100644 --- a/readme.md +++ b/readme.md @@ -1,148 +1,105 @@ -![PVP-Arena](/doc/images/logo.png) - - -**Enhance your server by adding a new dimension of PVP battles!** - -Create fully customizable, moddable, flexible arenas, develop your own arena goal or mod that totally changes the game as you wish. -This flexibility is achieved on the one hand by a module loader created by NodinChan which loads arena goals (/pvparena/goals) and arena mods (/pvparena/mods) which enhance the gameplay just limited by your imagination, on the other hand it features an API, which still is a WIP due to lack of requests. I will enhance it as feature/hook requests arise. +![PVP-Arena](doc/images/logo.png) +

+ + IF YOU'RE UPGRADING FROM 1.14.x VERSION OR BELOW, PLEASE READ + UPGRADE DOCUMENTATION + +

*** +[What is PVP Arena?](#What-is-PVP-Arena?) | [Dependencies](#Dependencies) | [Downloads](#Downloads) | +[Installation](#Installation) | [Documentation](#Documentation) | [Support](#Support) | +[Telemetry](#Telemetry) | [Credits](#Credits) +*** +
+## What is PVP Arena? -## Features +PVP Arena is a plugin for Spigot based servers which enables creation of customizable fight and mini-games arenas. +Define your own teams, classes, lobbies, spawn points, messages, gear colors, rewards and even game modes! +Theses game modes (included in the plugin) can combined with tens of modules to enhance your gameplay! +In addition, all arenas can be protected with an embedded protection system based on regions. +Anyway, here's a quick (non exhaustive) list of plugin features: - Multiple arenas -- Battlefield regions -- Customizable classes +- Arena regions and protections - Player-state saving -- Arena regions -- In-game configuration access -- Arena disable -- Leader boards +- Customizable classes +- Customizable spawn points, lobbies and spectator zones +- In-game configuration access and simple config files +- Arena disabling +- Scoreboards - Spawn protection - Flag coloring - Inventory drops - Announcements -- Arena end timer +- Time limited match +- Battlefield regeneration +So take time to read the docs, it's full of useful information 😉 *** ## Dependencies -- Spigot 1.11.2 +- Spigot 1.13+ +- Java 8+ *** ## Downloads -- [spigotmc.org](https://www.spigotmc.org/resources/pvp-arena.16584/) -- [jenkins - dev builds](https://ci2.craftyn.com/job/PVP%20Arena/) +PVP Arena release version can be downloaded on following pages: +- [PVP Arena - SpigotMC](https://www.spigotmc.org/resources/pvp-arena.16584/) +- [Github releases page](https://github.com/Eredrim/pvparena/releases) + +Development builds (experimental) can be downloaded on our discord: +- [Discord server](https://discord.gg/a8NhSsXKVQ) (channel #dev-builds) *** -## How to install +## Installation -- Stop your server -- Place jar in plugins folder -- Run a first time to create config folder -- Configure if you wish to -- Done ! +Place PVP Arena `.jar` file in the plugin repository of your server and restart. *** ## Documentation -- [Creation](doc/creation.md) +- [Getting started](doc/getting-started.md) - [Commands](doc/commands.md) -- [Enhancements](doc/enhancements.md) -- [Items](doc/items.md) -- [Languages](doc/languages.md) - [Permissions](doc/permissions.md) - [Regions](doc/regions.md) +- [Goals](doc/goals.md) +- [Modules](doc/modules.md) +- [Items in config files](doc/items.md) +- [Languages](doc/languages.md) - [Configuration](doc/configuration.md) +- [Update checker](doc/update-checker.md) +- [FAQ](doc/faq.md) *** -## Video Tutorials - -- Basic Setup (v1.3): - - [Team Arena](https://www.youtube.com/watch?v=PT0piAyVMIw) - - [Free For All Arena](https://www.youtube.com/watch?v=bYNtxGxVGfE) - - [Region Tutorial (Shapes)](https://www.youtube.com/watch?v=jWdWbwRg9zY) - - [Region Tutorial (Protections)](https://youtu.be/WFIZ7ZskPVc) -- Localized Setup (v1.3): - - [Team Arena (German)](https://www.youtube.com/watch?v=2KSAk-PvwRM) -- Goal Tutorials (v1.3): - - [BlockDestroy](https://www.youtube.com/watch?v=i7Fpuh_O5O8) - - [CheckPoints](https://www.youtube.com/watch?v=anO_tYwcKsg) - - [Domination](https://www.youtube.com/watch?v=_Ngq5xBlLsk) -- [CTF (v1.0)](http://www.youtube.com/watch?v=SuL78bce-f0) -- [DeathMatch (v1.0)](http://www.youtube.com/watch?v=KqBueDNbpD8) -- [Food Block Destroy (v1.0)](http://www.youtube.com/watch?v=ntloY1BTKHQ) -- [FreeForAll (v1.0)](http://www.youtube.com/watch?v=xBIxHoKMu98) -- [Spleef (v1.0)](http://www.youtube.com/watch?v=DRmLNXEAs_4) -- [Pillar Domination (v1.0)](http://www.youtube.com/watch?v=Xi7yNURxAjw) -- [TeamDeathMatch (v1.0)](http://www.youtube.com/watch?v=rQ1ljlc6SJM) - -Users tutorials : - -- [TeamDeathMatch (v1.0)](http://www.youtube.com/watch?v=Jw6E8s2kiKw) +## Support -*** - -## Changelog - -- v1.3.4.298 - attempt to properly back up NBT data of player's items in case of an unnatural leaving of the arena -- [read more](doc/changelog.md) - -*** - -## Todo - -- plugin - - [ ] calculate a winner based on ROUND results -- modules -- goals - - [ ] tournament arenas ; rounds switch through arenas - - [ ] siege -> bring PACKET from A to B || prevent - -*** +You can contact us to ask your questions or just discuss, you can go here: +- [Spigot Forums](https://www.spigotmc.org/threads/pvp-arena.113406/) +- [Discord server](https://discord.gg/a8NhSsXKVQ) -## Update Checker -I use two ways of keeping track of versions. One is the plugin version, the Bukkit Update Checker utilizing the Curse API, -the other setting is for module version checking, let me show you the important config.yml nodes: - - update: - modules: true - # should PA check my server (www.slipcor.net) for module versions? - # !! If you disable that, you have to manually download and install modules! !! - - type: beta #which release state do we want to use? - # valid values: - # alpha: update to every dev build - # beta: update to every beta build - # release: only update to full release builds - # everything else will fall back to release - - mode: both #how should we update? - # valid values: - # both: announce and download - # download: download, do not announce - # announce: only announce, do not download - # everything else will disable the update check +To report issues and make suggestion, please use our [Github issues page](https://github.com/Eredrim/pvparena/issues). *** -## Phoning home +## Telemetry -By default, the server contacts my private server for information purposes. It sends your port, IP (for proper server counting), and the plugin version. -That's it! If you want to disable that, set "tracker" to false in the config! +PVPArena uses bStats to get statistics about basic information like plugin version, java version, +kind of used Minecraft server, etc. You can disable it in the dedicated config file `/plugins/bStats/config.yml` *** ## Credits +- SlipCor, the wonderful guy who created this plugin - Deminetix for the very root, the Fight plugin - Bradley Hilton for the fork until version v0.0.3 - Carbon131 for adding features until version v0.0.5 diff --git a/src/config.yml b/src/config.yml index ab8df2c28..b9c8d4cd8 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,7 +1,6 @@ debug: none server_log: false stats: true -tracker: true language: en onlyPVPinArena: false safeadmin: true @@ -17,9 +16,8 @@ shortcut_shuffle: false allow_ungrouped: false consoleoffduty: false update: - mode: both - type: beta - modules: true + plugin: announce + modules: announce materialprefixes: - minecraft - bukkit diff --git a/src/net/slipcor/pvparena/PVPArena.java b/src/net/slipcor/pvparena/PVPArena.java index e62b6d324..54f419bbb 100644 --- a/src/net/slipcor/pvparena/PVPArena.java +++ b/src/net/slipcor/pvparena/PVPArena.java @@ -6,16 +6,24 @@ import net.slipcor.pvparena.classes.PACheck; import net.slipcor.pvparena.commands.*; import net.slipcor.pvparena.core.Config.CFG; -import net.slipcor.pvparena.core.*; +import net.slipcor.pvparena.core.Debug; +import net.slipcor.pvparena.core.Help; +import net.slipcor.pvparena.core.Language; import net.slipcor.pvparena.core.Language.MSG; +import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.listeners.BlockListener; import net.slipcor.pvparena.listeners.EntityListener; import net.slipcor.pvparena.listeners.InventoryListener; import net.slipcor.pvparena.listeners.PlayerListener; -import net.slipcor.pvparena.loadables.*; +import net.slipcor.pvparena.loadables.ArenaGoalManager; +import net.slipcor.pvparena.loadables.ArenaModule; +import net.slipcor.pvparena.loadables.ArenaModuleManager; +import net.slipcor.pvparena.loadables.ArenaRegionShapeManager; import net.slipcor.pvparena.managers.ArenaManager; import net.slipcor.pvparena.managers.StatisticsManager; import net.slipcor.pvparena.managers.TabManager; +import net.slipcor.pvparena.updater.UpdateChecker; +import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -42,7 +50,8 @@ public class PVPArena extends JavaPlugin { public static PVPArena instance; - private static Debug DEBUG; + private static Debug debugger; + private static final int BSTATS_PLUGIN_ID = 5067; private ArenaGoalManager agm; private ArenaModuleManager amm; @@ -51,7 +60,7 @@ public class PVPArena extends JavaPlugin { private final List arenaCommands = new ArrayList<>(); private final List globalCommands = new ArrayList<>(); - private Updater updater; + private UpdateChecker updateChecker; private boolean shuttingDown; /** @@ -89,8 +98,8 @@ public List getGlobalCommands() { return globalCommands; } - public Updater getUpdater() { - return updater; + public UpdateChecker getUpdateChecker() { + return updateChecker; } /** @@ -198,17 +207,18 @@ private void loadArenaCommands() { arenaCommands.add(new PAI_Shutup()); arenaCommands.add(new PAG_Arenaclass()); arenaCommands.add(new PAI_Info()); + arenaCommands.add(new PAI_Stats()); } private void loadGlobalCommands() { globalCommands.add(new PAA_Create()); globalCommands.add(new PAA_Debug()); globalCommands.add(new PAA_Duty()); - globalCommands.add(new PAI_Help()); - globalCommands.add(new PAA_Install()); - globalCommands.add(new PAA_Uninstall()); - globalCommands.add(new PAA_Update()); + globalCommands.add(new PAA_Modules()); + globalCommands.add(new PAA_ReloadAll()); globalCommands.add(new PAI_ArenaList()); + globalCommands.add(new PAI_GlobalStats()); + globalCommands.add(new PAI_Help()); globalCommands.add(new PAI_Version()); } @@ -253,59 +263,12 @@ public boolean onCommand(final CommandSender sender, final Command cmd, } } final ArenaPlayer player = ArenaPlayer.parsePlayer(sender.getName()); - if (pacmd != null - && !(player.getArena() != null && pacmd.getName() - .contains("PAI_ArenaList"))) { - DEBUG.i("committing: " + pacmd.getName(), sender); + if (pacmd != null && !(player.getArena() != null && pacmd.hasVersionForArena())) { + debugger.i("committing: " + pacmd.getName(), sender); pacmd.commit(sender, StringParser.shiftArrayBy(args, 1)); return true; } - if ("-s".equalsIgnoreCase(args[0]) || "stats".equalsIgnoreCase(args[0])) { - final PAI_Stats scmd = new PAI_Stats(); - DEBUG.i("committing: " + scmd.getName(), sender); - scmd.commit(null, sender, StringParser.shiftArrayBy(args, 1)); - return true; - } - if (args.length > 1 - && (args[1].equalsIgnoreCase("-s") || args[1] - .equalsIgnoreCase("stats"))) { - final PAI_Stats scmd = new PAI_Stats(); - DEBUG.i("committing: " + scmd.getName(), sender); - scmd.commit(ArenaManager.getIndirectArenaByName(sender, args[0]), sender, - StringParser.shiftArrayBy(args, 2)); - return true; - } - if (args[0].equalsIgnoreCase("!rl") - || args[0].toLowerCase().contains("reload")) { - final PAA_Reload scmd = new PAA_Reload(); - DEBUG.i("committing: " + scmd.getName(), sender); - - this.reloadConfig(); - - Language.init(getConfig().getString("language", "en")); - Help.init(getConfig().getString("language", "en")); - - if (args.length > 1 && args[1].equalsIgnoreCase("ymls")) { - Arena.pmsg(sender, Language.parse(MSG.RELOAD_YMLS_DONE)); - return true; - } - - final String[] emptyArray = new String[0]; - - for (Arena a : ArenaManager.getArenas()) { - scmd.commit(a, sender, emptyArray); - } - - ArenaManager.load_arenas(); - if (getConfig().getBoolean("use_shortcuts") || - getConfig().getBoolean("only_shortcuts")) { - ArenaManager.readShortcuts(getConfig().getConfigurationSection("shortcuts")); - } - - return true; - } - Arena tempArena = "l".equalsIgnoreCase(args[0])?player.getArena():ArenaManager.getIndirectArenaByName(sender, args[0]); final String name = args[0]; @@ -366,20 +329,14 @@ public boolean onCommand(final CommandSender sender, final Command cmd, break; } } - if (paacmd == null - && PACheck.handleCommand(tempArena, sender, newArgs)) { + if (paacmd == null && PACheck.handleCommand(tempArena, sender, newArgs)) { return true; } - if (paacmd == null - && tempArena.getArenaConfig().getBoolean(CFG.CMDS_DEFAULTJOIN)) { + if (paacmd == null && tempArena.getArenaConfig().getBoolean(CFG.CMDS_DEFAULTJOIN) && args.length == 1) { paacmd = new PAG_Join(); - if (newArgs.length > 1) { - newArgs = StringParser.shiftArrayBy(newArgs, 1); - } - tempArena.getDebugger() - .i("committing: " + paacmd.getName(), sender); - paacmd.commit(tempArena, sender, newArgs); + tempArena.getDebugger().i("committing: " + paacmd.getName(), sender); + paacmd.commit(tempArena, sender, new String[0]); return true; } @@ -404,17 +361,19 @@ public List onTabComplete(final CommandSender sender, final Command cmd, public void onDisable() { shuttingDown = true; ArenaManager.reset(true); - Tracker.stop(); Debug.destroy(); - Language.logInfo(MSG.LOG_PLUGIN_DISABLED, getDescription() - .getFullName()); + this.getUpdateChecker().runOnDisable(); + Language.logInfo(MSG.LOG_PLUGIN_DISABLED, getDescription().getFullName()); } @Override public void onEnable() { shuttingDown = false; instance = this; - DEBUG = new Debug(1); + debugger = new Debug(1); + + //Enable bStats + Metrics metrics = new Metrics(this, BSTATS_PLUGIN_ID); saveDefaultConfig(); if (!getConfig().contains("shortcuts")) { @@ -434,13 +393,11 @@ public void onEnable() { saveConfig(); } - if (!getConfig().contains("update.mode") && getConfig().contains("modulecheck")) { - getConfig().set("update.mode", getConfig().getString("update", "both")); - getConfig().set("update.type", getConfig().getString("updatetype", "beta")); - getConfig().set("update.modules", getConfig().getBoolean("modulecheck", true)); - - getConfig().set("modulecheck", null); - getConfig().set("updatetype", null); + if (getConfig().contains("update.type") || getConfig().contains("update.mode")) { + getConfig().set("update.plugin", getConfig().getString("update.mode", "announce")); + getConfig().set("update.modules", getConfig().getBoolean("update.modules", true) ? "download" : "announce"); + getConfig().set("update.type", null); + getConfig().set("update.mode", null); saveConfig(); } @@ -456,9 +413,9 @@ public void onEnable() { FileConfiguration cfg = getConfig(); List toDelete = cfg.getStringList("todelete"); - if (toDelete != null){ + if (!toDelete.isEmpty()){ for (String jar : toDelete) { - PAA_Uninstall.remove(jar); + PAA_Modules.remove(jar); } cfg.set("todelete", null); saveConfig(); @@ -475,7 +432,6 @@ public void onEnable() { Help.init(getConfig().getString("language", "en")); StatisticsManager.initialize(); - ArenaPlayer.initiate(); getServer().getPluginManager() .registerEvents(new BlockListener(), this); @@ -501,14 +457,7 @@ public void onEnable() { ArenaManager.readShortcuts(getConfig().getConfigurationSection("shortcuts")); } - updater = new Updater(this, getFile()); - - if (ArenaManager.count() > 0) { - if (PVPArena.instance.getConfig().getBoolean("tracker", true)) { - final Tracker trackMe = new Tracker(); - trackMe.start(); - } - } + updateChecker = new UpdateChecker(this.getFile()); Language.logInfo(MSG.LOG_PLUGIN_ENABLED, getDescription().getFullName()); } diff --git a/src/net/slipcor/pvparena/arena/Arena.java b/src/net/slipcor/pvparena/arena/Arena.java index 4e2e18e70..7aa3a1ea5 100644 --- a/src/net/slipcor/pvparena/arena/Arena.java +++ b/src/net/slipcor/pvparena/arena/Arena.java @@ -1,6 +1,5 @@ package net.slipcor.pvparena.arena; -import com.google.common.collect.ImmutableMap; import net.slipcor.pvparena.PVPArena; import net.slipcor.pvparena.arena.ArenaPlayer.Status; import net.slipcor.pvparena.classes.*; @@ -19,6 +18,7 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.attribute.Attribute; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; @@ -35,12 +35,18 @@ import org.bukkit.plugin.IllegalPluginAccessException; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scoreboard.*; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; import org.bukkit.util.Vector; import java.io.File; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Optional.ofNullable; /** *
@@ -219,7 +225,7 @@ public void addRegion(final ArenaRegion region) {
             if (cfg.getBoolean(CFG.JOIN_FORCE)) {
                 region.initTimer();
             }
-        } else if (region.getType() == RegionType.WATCH) {
+        } else if (region.getType() == RegionType.WATCH || region.getType() == RegionType.LOUNGE) {
             region.initTimer();
         }
     }
@@ -410,15 +416,9 @@ public Player getEntityOwner(final Entity entity) {
      * hand over everyone being part of the arena
      */
     public Set getEveryone() {
-
-        final Set players = new HashSet<>();
-
-        for (final ArenaPlayer ap : ArenaPlayer.getAllArenaPlayers()) {
-            if (equals(ap.getArena())) {
-                players.add(ap);
-            }
-        }
-        return players;
+        return ArenaPlayer.getAllArenaPlayers().stream()
+                .filter(ap -> this.equals(ap.getArena()))
+                .collect(Collectors.toSet());
     }
 
     /**
@@ -485,14 +485,12 @@ public String getPrefix() {
 
     public Material getReadyBlock() {
         getDebugger().i("reading ready block");
-        final String sMat = cfg.getString(CFG.READY_BLOCK);
         try {
-            Material mMat;
-            mMat = Material.getMaterial(sMat);
+            Material mMat = cfg.getMaterial(CFG.READY_BLOCK, Material.STICK);
             getDebugger().i("mMat now is " + mMat.name());
             return mMat;
         } catch (final Exception e) {
-            Language.logWarn(MSG.ERROR_MAT_NOT_FOUND, sMat);
+            Language.logWarn(MSG.ERROR_MAT_NOT_FOUND, "ready block");
         }
         return Material.IRON_BLOCK;
     }
@@ -531,86 +529,63 @@ public Set getSpawns() {
     }
 
     private Scoreboard getSpecialScoreboard() {
-        if (scoreboard == null) {
-            scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
-/*
-            Objective oBM = Bukkit.getScoreboardManager().getMainScoreboard().getObjective(DisplaySlot.BELOW_NAME);
-            if (oBM != null) {
-                oBM = scoreboard.registerNewObjective(oBM.getCriteria(), oBM.getDisplayName());
-                oBM.setDisplaySlot(DisplaySlot.BELOW_NAME);
-
-            }
-
-            Objective oTB = Bukkit.getScoreboardManager().getMainScoreboard().getObjective(DisplaySlot.PLAYER_LIST);
-            if (oTB != null) {
-                oTB = scoreboard.registerNewObjective(oTB.getCriteria(), oTB.getDisplayName());
-                oTB.setDisplaySlot(DisplaySlot.PLAYER_LIST);
-            }
-*/
-            for (final ArenaTeam team : getTeams()) {
-
-                try {
-                    scoreboard.registerNewTeam(team.getName());
-                    final Team bukkitTeam = scoreboard.getTeam(team.getName());
-                    if (!getArenaConfig().getBoolean(CFG.PLAYER_COLLISION)) {
-                        bukkitTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
-                    }
-                    bukkitTeam.setPrefix(team.getColor().toString());
-                    bukkitTeam.addEntry(team.getName());
-                    bukkitTeam.setAllowFriendlyFire(getArenaConfig().getBoolean(CFG.PERMS_TEAMKILL));
+        if (this.scoreboard == null) {
+            this.scoreboard = this.getCommonScoreboard(true);
 
-                    bukkitTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
-                } catch (final Exception e) {
-                    e.printStackTrace();
-                }
-            }
+            // length = 18 without arena name
+            String sbHeaderPrefix = ChatColor.GREEN + "PVP Arena" + ChatColor.RESET + " - " + ChatColor.YELLOW;
+            String sbHeaderName = sbHeaderPrefix + this.getName();
 
-            if (scoreboard.getObjective("lives") != null) {
-                scoreboard.getObjective("lives").unregister();
-                if (scoreboard.getObjective(DisplaySlot.SIDEBAR) != null) {
-                    scoreboard.getObjective(DisplaySlot.SIDEBAR).unregister();
+            if (sbHeaderName.length() > 32) {
+                if (this.prefix.length() <= 14) {
+                    sbHeaderName = sbHeaderPrefix + this.prefix;
+                } else {
+                    sbHeaderName = sbHeaderName.substring(0, 32);
                 }
             }
 
-            Objective obj = scoreboard.registerNewObjective("lives", "dummy"); //deathCount
-
-            String name = ChatColor.GREEN + "PVP Arena" + ChatColor.RESET + " - " + ChatColor.YELLOW + getName();
-
-            if (name.length() > 32) {
-                if (prefix.length() < getName().length()) {
-                    name = ChatColor.GREEN + "PVP Arena" + ChatColor.RESET + " - " + ChatColor.YELLOW + prefix;
-                } else {
-                    name = name.substring(0, 32);
+            if (this.scoreboard.getObjective("lives") != null) {
+                this.scoreboard.getObjective("lives").unregister();
+                if (this.scoreboard.getObjective(DisplaySlot.SIDEBAR) != null) {
+                    this.scoreboard.getObjective(DisplaySlot.SIDEBAR).unregister();
                 }
             }
-            obj.setDisplayName(name);
+            Objective obj = this.scoreboard.registerNewObjective("lives", "dummy", sbHeaderName); //deathCount
 
             if (this.isFightInProgress()) {
                 obj.setDisplaySlot(DisplaySlot.SIDEBAR);
             }
         }
-        return scoreboard;
+        return this.scoreboard;
     }
 
     private Scoreboard getStandardScoreboard() {
-        if (scoreboard == null) {
-            scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
-            for (final ArenaTeam team : getTeams()) {
-                final Team sTeam = scoreboard.registerNewTeam(team.getName());
-                sTeam.setPrefix(team.getColor().toString());
-                sTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
-                if (!getArenaConfig().getBoolean(CFG.PLAYER_COLLISION)) {
-                    sTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
+        if (this.scoreboard == null) {
+            return this.getCommonScoreboard(false);
+        }
+        return this.scoreboard;
+    }
+
+    private Scoreboard getCommonScoreboard(boolean addTeamEntry) {
+        if (this.scoreboard == null) {
+            this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
+            for (final ArenaTeam team : this.getTeams()) {
+                final Team sbTeam = this.scoreboard.registerNewTeam(team.getName());
+                sbTeam.setPrefix(team.getColor().toString());
+                sbTeam.setSuffix(ChatColor.RESET.toString());
+                sbTeam.setColor(team.getColor());
+                sbTeam.setCanSeeFriendlyInvisibles(!this.isFreeForAll());
+                sbTeam.setAllowFriendlyFire(this.getArenaConfig().getBoolean(CFG.PERMS_TEAMKILL));
+                if (!this.getArenaConfig().getBoolean(CFG.PLAYER_COLLISION)) {
+                    sbTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
                 }
-                for (final ArenaPlayer aPlayer : team.getTeamMembers()) {
-                    sTeam.addEntry(aPlayer.getName());
+
+                if(addTeamEntry) {
+                    sbTeam.addEntry(team.getName());
                 }
-            } /*
-            for (Objective o : scoreboard.getObjectives()) {
-                o.setDisplaySlot(DisplaySlot.PLAYER_LIST);
-            } */
+            }
         }
-        return scoreboard;
+        return this.scoreboard;
     }
 
     public ArenaTeam getTeam(final String name) {
@@ -685,12 +660,8 @@ public void giveRewards(final Player player) {
         getDebugger().i("giving rewards to " + player.getName(), player);
 
         ArenaModuleManager.giveRewards(this, player);
-        final String sItems = cfg.getString(CFG.ITEMS_REWARDS, "none");
+        ItemStack[] items = cfg.getItems(CFG.ITEMS_REWARDS);
 
-        String[] items = sItems.split(",");
-        if ("none".equals(sItems)) {
-            items = null;
-        }
         final boolean isRandom = cfg.getBoolean(CFG.ITEMS_RANDOM);
         final Random rRandom = new Random();
 
@@ -711,7 +682,7 @@ public void giveRewards(final Player player) {
             if (items[i] == null) {
                 continue;
             }
-            final ItemStack stack = StringParser.getItemStackFromString(items[i]);
+            final ItemStack stack = items[i];
             if (stack == null) {
                 PVPArena.instance.getLogger().warning(
                         "unrecognized item: " + items[i]);
@@ -823,7 +794,7 @@ public boolean isFightInProgress() {
     }
 
     public boolean isFreeForAll() {
-        return free;
+        return this.free;
     }
 
     public boolean isLocked() {
@@ -894,6 +865,7 @@ public String parseDeathCause(final Player player, final DamageCause cause,
 
         switch (cause) {
             case ENTITY_ATTACK:
+            case ENTITY_SWEEP_ATTACK:
                 if (damager instanceof Player && team != null) {
                     return team.colorizePlayer(aPlayer.get()) + ChatColor.YELLOW;
                 }
@@ -946,8 +918,7 @@ public String parseDeathCause(final Player player, final DamageCause cause,
             default:
                 break;
         }
-        MSG string = MSG.getByName("DEATHCAUSE_"
-                + cause.toString());
+        MSG string = MSG.getByName("DEATHCAUSE_" + cause.toString());
         if (string == null) {
             PVPArena.instance.getLogger().warning("Unknown cause: " + cause.toString());
             string = MSG.DEATHCAUSE_VOID;
@@ -964,22 +935,6 @@ public static void pmsg(final CommandSender sender, final String msg) {
         sender.sendMessage(Language.parse(MSG.MESSAGES_GENERAL, PVPArena.instance.getConfig().getString("globalPrefix", "PVP Arena"), msg));
     }
 
-    /**
-     * @deprecated use {@link #playerLeave(Player, CFG, boolean, boolean), boolean}
-     */
-    @Deprecated
-    public void playerLeave(final Player player, final CFG location, final boolean silent) {
-        playerLeave(player, location, silent, !silent, silent);
-    }
-
-    /**
-     * @deprecated use {@link #playerLeave(Player, CFG, boolean, boolean), boolean}
-     */
-    @Deprecated
-    public void playerLeave(final Player player, final CFG location, final boolean silent, final boolean force) {
-        playerLeave(player, location, silent, force, !force);
-    }
-
     /**
      * a player leaves from the arena
      *
@@ -1327,46 +1282,50 @@ public void resetPlayers(final boolean force) {
     }
 
     private void resetScoreboard(final Player player, final boolean force, final boolean soft) {
-        if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
-            getDebugger().i("ScoreBoards: "+(soft?"(soft) ":"")+"remove: " + player.getName(), player);
+        if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+            this.getDebugger().i("ScoreBoards: "+(soft?"(soft) ":"")+"remove: " + player.getName(), player);
             try {
-                if (scoreboard != null) {
-                    for (final Team team : scoreboard.getTeams()) {
+                if (this.scoreboard != null) {
+                    for (final Team team : this.scoreboard.getTeams()) {
                         if (team.hasEntry(player.getName())) {
                             team.removeEntry(player.getName());
                             if (soft) {
-                                updateScoreboards();
+                                this.updateScoreboards();
                                 return;
                             }
-                            scoreboard.resetScores(player.getName());
+                            this.scoreboard.resetScores(player.getName());
                         }
                     }
                 } else {
-                    getDebugger().i("ScoreBoards: scoreboard is null!");
+                    this.getDebugger().i("ScoreBoards: scoreboard is null!");
                     return;
                 }
+
                 final ArenaPlayer ap = ArenaPlayer.parsePlayer(player.getName());
-                class RunLater implements Runnable {
-                    @Override
-                    public void run() {
-                        if (ap.hasBackupScoreboard()) {
-                            player.setScoreboard(ap.getBackupScoreboard());
+                if (ap.hasBackupScoreboard()) {
+                    this.getDebugger().i("ScoreBoards: restoring " + ap.get());
+
+                    class RunLater extends BukkitRunnable {
+                        @Override
+                        public void run() {
+                            Scoreboard backupScoreboard = ap.getBackupScoreboard();
                             if (ap.getBackupScoreboardTeam() != null && !force) {
-                                ap.getBackupScoreboardTeam().addEntry(ap.getName());
+                                backupScoreboard.getTeam(ap.getBackupScoreboardTeam()).addEntry(ap.getName());
                             }
+                            player.setScoreboard(backupScoreboard);
                             ap.setBackupScoreboardTeam(null);
                             ap.setBackupScoreboard(null);
                         }
                     }
-                }
-                getDebugger().i("ScoreBoards: maybe restoring " + ap.get());
-                if (force) {
-                    new RunLater().run();
-                } else {
-                    try {
-                        Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RunLater(), 2L);
-                    } catch (IllegalStateException e) {
 
+                    if (force) {
+                        new RunLater().run();
+                    } else {
+                        try {
+                            new RunLater().runTaskLater(PVPArena.instance, 2L);
+                        } catch (IllegalStateException ignored) {
+
+                        }
                     }
                 }
 
@@ -1374,7 +1333,7 @@ public void run() {
                 e.printStackTrace();
             }
         } else {
-            Team team = getStandardScoreboard().getEntryTeam(player.getName());
+            Team team = this.getStandardScoreboard().getEntryTeam(player.getName());
             if (team != null) {
                 team.removeEntry(player.getName());
                 if (soft) {
@@ -1382,23 +1341,19 @@ public void run() {
                 }
             }
             final ArenaPlayer ap = ArenaPlayer.parsePlayer(player.getName());
-            try {
-                Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
-                    @Override
-                    public void run() {
-
-                        if (ap.hasBackupScoreboard()) {
-                            player.setScoreboard(ap.getBackupScoreboard());
-                            if (ap.getBackupScoreboardTeam() != null) {
-                                ap.getBackupScoreboardTeam().addEntry(ap.getName());
-                            }
-                            ap.setBackupScoreboardTeam(null);
-                            ap.setBackupScoreboard(null);
+            if (ap.hasBackupScoreboard()) {
+                try {
+                    Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+                        Scoreboard backupScoreboard = ap.getBackupScoreboard();
+                        if (ap.getBackupScoreboardTeam() != null) {
+                            backupScoreboard.getTeam(ap.getBackupScoreboardTeam()).addEntry(ap.getName());
                         }
-                    }
-                }, 3L);
-            } catch (IllegalPluginAccessException e) {
+                        player.setScoreboard(backupScoreboard);
+                        ap.setBackupScoreboardTeam(null);
+                    }, 3L);
+                } catch (IllegalPluginAccessException ignored) {
 
+                }
             }
         }
     }
@@ -1528,10 +1483,10 @@ public boolean removeCustomScoreBoardEntry(final ArenaModule module, final int v
      * reset a player to his pre-join values
      *
      * @param player the player to reset
-     * @param string the teleport location
+     * @param destination the teleport location
      * @param soft   if location should be preserved (another tp incoming)
      */
-        private void resetPlayer(final Player player, final String string, final boolean soft,
+    private void resetPlayer(final Player player, final String destination, final boolean soft,
                              final boolean force) {
         if (player == null) {
             return;
@@ -1548,30 +1503,28 @@ private void resetPlayer(final Player player, final String string, final boolean
         if (aPlayer.getState() != null) {
             aPlayer.getState().unload(soft);
         }
-        resetScoreboard(player, force, soft);
+        this.resetScoreboard(player, force, soft);
 
         //noinspection deprecation
-        ArenaModuleManager.resetPlayer(this, player, force);
         ArenaModuleManager.resetPlayer(this, player, soft, force);
 
-        String sClass = "";
-        if (aPlayer.getArenaClass() != null) {
-            sClass = aPlayer.getArenaClass().getName();
-        }
-
-        if (!soft && (!"custom".equalsIgnoreCase(sClass) ||
-                cfg.getBoolean(CFG.GENERAL_CUSTOMRETURNSGEAR))) {
+        if (!soft && (!aPlayer.hasCustomClass() || cfg.getBoolean(CFG.GENERAL_CUSTOMRETURNSGEAR))) {
             ArenaPlayer.reloadInventory(this, player, true);
         }
 
+        this.teleportPlayerAfterReset(destination, soft, force, aPlayer);
+    }
+
+    private void teleportPlayerAfterReset(final String destination, final boolean soft, final boolean force, final ArenaPlayer aPlayer) {
+        final Player player = aPlayer.get();
         class RunLater implements Runnable {
 
             @Override
             public void run() {
-                getDebugger().i("string = " + string, player);
+                getDebugger().i("string = " + destination, player);
                 aPlayer.setTelePass(true);
 
-                if ("old".equalsIgnoreCase(string)) {
+                if ("old".equalsIgnoreCase(destination)) {
                     getDebugger().i("tping to old", player);
                     if (aPlayer.getSavedLocation() != null) {
                         getDebugger().i("location is fine", player);
@@ -1584,13 +1537,13 @@ public void run() {
                         aPlayer.setTeleporting(false);
                     }
                 } else {
-                    Location offset = getOffset(string);
+                    Location offset = getOffset(destination);
                     if (offset == null) {
                         offset = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
                     }
-                    final PALocation loc = SpawnManager.getSpawnByExactName(Arena.this, string);
+                    final PALocation loc = SpawnManager.getSpawnByExactName(Arena.this, destination);
                     if (loc == null) {
-                        new Exception("RESET Spawn null: " + getName() + "->" + string).printStackTrace();
+                        new Exception("RESET Spawn null: " + getName() + "->" + destination).printStackTrace();
                     } else {
                         player.teleport(loc.toLocation().add(offset.toVector()));
                         aPlayer.setTelePass(false);
@@ -1613,92 +1566,51 @@ public void run() {
         final RunLater runLater = new RunLater();
 
         aPlayer.setTeleporting(true);
-        if (cfg.getInt(CFG.TIME_RESETDELAY) > -1 && !force) {
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, runLater, cfg.getInt(CFG.TIME_RESETDELAY));
-        } else {
+        if (cfg.getInt(CFG.TIME_RESETDELAY) > 0 && !force) {
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, runLater, cfg.getInt(CFG.TIME_RESETDELAY) * 20);
+        } else if (PVPArena.instance.isShuttingDown()) {
             runLater.run();
+        } else {
+            // Waiting two ticks in order to avoid player death bug
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, runLater, 2);
         }
     }
 
-    public void setupScoreboard(final Player player) {
-        if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
-            final ArenaPlayer ap = ArenaPlayer.parsePlayer(player.getName());
-            getDebugger().i("ScoreBoards: Initiating scoreboard for player " + player.getName());
-            if (!ap.hasBackupScoreboard() && player.getScoreboard() != null) {
-                ap.setBackupScoreboard(player.getScoreboard());
-                ap.setBackupScoreboardTeam(player.getScoreboard().getEntryTeam(ap.getName()));
-            } else if (ap.hasBackupScoreboard()) {
-                getDebugger().i("ScoreBoards: has backup: " + ap.hasBackupScoreboard());
-                getDebugger().i("ScoreBoards: player.getScoreboard == null: " + (player.getScoreboard() == null));
-            } else {
-                getDebugger().i("ScoreBoards: has backup: false");
-                getDebugger().i("ScoreBoards: player.getScoreboard == null: " + (player.getScoreboard() == null));
-            }
+    public void setupScoreboard(final ArenaPlayer ap) {
+        Player player = ap.get();
 
-            // first, check if the scoreboard exists
-            class RunLater implements Runnable {
-                final Scoreboard board = getSpecialScoreboard();
-                @Override
-                public void run() {
+        this.getDebugger().i("ScoreBoards: Initiating scoreboard for player " + player.getName());
+        this.getDebugger().i("ScoreBoards: has backup: " + ap.hasBackupScoreboard());
+        this.getDebugger().i("ScoreBoards: player.getScoreboard == null: " + (player.getScoreboard() == null));
+        if (!ap.hasBackupScoreboard() && player.getScoreboard() != null) {
+            ap.setBackupScoreboard(player.getScoreboard());
+            ofNullable(player.getScoreboard().getEntryTeam(ap.getName())).ifPresent(team ->
+                    ap.setBackupScoreboardTeam(team.getName())
+            );
+        }
 
+        if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+                final Scoreboard board = this.getSpecialScoreboard();
 
-                    for (final ArenaTeam team : getTeams()) {
+                Optional optBoardTeam = ofNullable(ap.getArenaTeam()).map(team -> board.getTeam(team.getName()));
+                optBoardTeam.ifPresent(boardTeam -> boardTeam.addEntry(player.getName()));
 
-                        if (team == ArenaPlayer.parsePlayer(player.getName()).getArenaTeam()) {
-                            board.getTeam(team.getName()).addEntry(player.getName());
-                            updateScoreboard(player);
-                            return;
-                        }
-                    }
-                    try {
-                        ArenaTeam team = ap.getArenaTeam();
-                        if (team == null) {
-                            updateScoreboard(player);
-                            return;
-                        }
-                        scoreboard.registerNewTeam(team.getName());
-                        final Team bukkitTeam = scoreboard.getTeam(team.getName());
-                        bukkitTeam.setPrefix(team.getColor().toString());
-                        bukkitTeam.addEntry(team.getName());
-                        bukkitTeam.setAllowFriendlyFire(getArenaConfig().getBoolean(CFG.PERMS_TEAMKILL));
-                        bukkitTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
-                    } catch (final Exception e) {
-                        e.printStackTrace();
-                    }
+                this.updateScoreboard(player);
 
-                    if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARDROUNDDISPLAY)) {
-                        addCustomScoreBoardEntry(null, Language.parse(MSG.ROUNDS_DISPLAY,
-                                String.valueOf(getRound()),
-                                String.valueOf(getRoundCount())),  199);
-                        addCustomScoreBoardEntry(null, Language.parse(MSG.ROUNDS_DISPLAYSEPARATOR), 198);
-                    }
+                if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARDROUNDDISPLAY)) {
+                    this.addCustomScoreBoardEntry(null, Language.parse(MSG.ROUNDS_DISPLAY,
+                            String.valueOf(this.getRound()),
+                            String.valueOf(this.getRoundCount())),  199);
+                    this.addCustomScoreBoardEntry(null, Language.parse(MSG.ROUNDS_DISPLAYSEPARATOR), 198);
                 }
-
-            }
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RunLater(), 1L);
+            }, 1L);
         } else {
-            final Scoreboard board = getStandardScoreboard();
-            ArenaPlayer ap = ArenaPlayer.parsePlayer(player.getName());
-            final ArenaTeam team = ap.getArenaTeam();
-            if (!ap.hasBackupScoreboard() && player.getScoreboard() != null) {
-                ap.setBackupScoreboard(player.getScoreboard());
-                ap.setBackupScoreboardTeam(player.getScoreboard().getEntryTeam(ap.getName()));
-            }
+            final Scoreboard board = this.getStandardScoreboard();
 
             player.setScoreboard(board);
-            if (team == null) {
-                return;
-            }
-            for (final Team sTeam : board.getTeams()) {
-                if (sTeam.getName().equals(team.getName())) {
-                    sTeam.addEntry(player.getName());
-                    return;
-                }
-            }
-            final Team sTeam = board.registerNewTeam(team.getName());
-            sTeam.setPrefix(team.getColor().toString());
-            sTeam.addEntry(player.getName());
-            sTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
+            Optional optBoardTeam = ofNullable(ap.getArenaTeam()).map(team -> board.getTeam(team.getName()));
+            optBoardTeam.ifPresent(boardTeam -> boardTeam.addEntry(player.getName()));
         }
     }
 
@@ -1710,17 +1622,16 @@ public void run() {
     public void unKillPlayer(final Player player, final DamageCause cause, final Entity damager) {
 
         getDebugger().i("respawning player " + player.getName(), player);
-        int iHealth = cfg.getInt(CFG.PLAYER_HEALTH, -1);
+        double iHealth = cfg.getInt(CFG.PLAYER_HEALTH, -1);
 
         if (iHealth < 1) {
-            iHealth = (int) player.getMaxHealth();
+            iHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
         }
 
         PlayerState.playersetHealth(player, iHealth);
         player.setFoodLevel(cfg.getInt(CFG.PLAYER_FOODLEVEL, 20));
         player.setSaturation(cfg.getInt(CFG.PLAYER_SATURATION, 20));
-        player.setExhaustion((float) cfg.getDouble(
-                CFG.PLAYER_EXHAUSTION, 0.0));
+        player.setExhaustion((float) cfg.getDouble(CFG.PLAYER_EXHAUSTION, 0.0));
         player.setVelocity(new Vector());
         player.setFallDistance(0);
 
@@ -1869,7 +1780,7 @@ public void spawnCampPunish() {
                                 .setLastDamageCause(
                                         new EntityDamageEvent(locationArenaPlayerEntry.getValue().get(),
                                                 DamageCause.CUSTOM,
-                                                new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(1002))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0))));
+                                                1002));
                         locationArenaPlayerEntry.getValue()
                                 .get()
                                 .damage(cfg.getInt(
@@ -2022,18 +1933,35 @@ public String toString() {
         return name;
     }
 
+    public void tpPlayerToCoordName(ArenaPlayer player, String place) {
+        Location destination = this.prepareTeleportation(player, place);
+        this.teleportPlayer(place, player, destination);
+        this.execPostTeleportationFixes(player);
+    }
+
     /**
      * teleport a given player to the given coord string
      *
      * @param player the player to teleport
      * @param place  the coord string
      */
-    public void tpPlayerToCoordName(final Player player, final String place) {
+    public void tpPlayerToCoordNameForJoin(final ArenaPlayer player, final String place, boolean async) {
+        Location destination = this.prepareTeleportation(player, place);
+        int delay = async ? 2 : 0;
+        Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+            teleportPlayer(place, player, destination);
+            setupScoreboard(player);
+        }, delay);
+        this.execPostTeleportationFixes(player);
+    }
+
+    private Location prepareTeleportation(ArenaPlayer aPlayer, String place) {
+        Player player = aPlayer.get();
         getDebugger().i("teleporting " + player + " to coord " + place, player);
 
         if (player == null) {
             PVPArena.instance.getLogger().severe("Player null!");
-            return;
+            throw new RuntimeException("Player null!");
         }
 
         if (player.isInsideVehicle()) {
@@ -2042,8 +1970,6 @@ public void tpPlayerToCoordName(final Player player, final String place) {
 
         ArenaModuleManager.tpPlayerToCoordName(this, player, place);
 
-        final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
-
         if ("spectator".equals(place)) {
             if (getFighters().contains(aPlayer)) {
                 aPlayer.setStatus(Status.LOST);
@@ -2056,8 +1982,7 @@ public void tpPlayerToCoordName(final Player player, final String place) {
             loc = aPlayer.getSavedLocation();
         }
         if (loc == null) {
-            new Exception("TP Spawn null: " + name + "->" + place).printStackTrace();
-            return;
+            throw new RuntimeException("TP Spawn null: " + name + "->" + place);
         }
 
         debug.i("raw location: " + loc.toString());
@@ -2070,27 +1995,13 @@ public void tpPlayerToCoordName(final Player player, final String place) {
 
         aPlayer.setTeleporting(true);
         aPlayer.setTelePass(true);
-        player.teleport(loc.toLocation().add(offset.getX(),offset.getY(),offset.getZ()));
-        player.setNoDamageTicks(cfg.getInt(CFG.TIME_TELEPORTPROTECT) * 20);
-        if (place.contains("lounge")) {
-            getDebugger().i("setting TelePass later!");
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
-                @Override
-                public void run() {
-                    aPlayer.setTelePass(false);
-                    aPlayer.setTeleporting(false);
-                }
-            }, cfg.getInt(CFG.TIME_TELEPORTPROTECT) * 20);
-
-        } else {
-            getDebugger().i("setting TelePass now!");
-            aPlayer.setTelePass(false);
-            aPlayer.setTeleporting(false);
-        }
+        return loc.toLocation().add(offset.getX(), offset.getY(), offset.getZ());
+    }
 
+    private void execPostTeleportationFixes(ArenaPlayer aPlayer) {
         if (cfg.getBoolean(CFG.PLAYER_REMOVEARROWS)) {
             try {
-                new ArrowHack(player);
+                new ArrowHack(aPlayer.get());
             } catch (final Exception e) {
             }
         }
@@ -2104,7 +2015,7 @@ public void run() {
                 public void run() {
                     for (final ArenaPlayer player : getFighters()) {
                         if (player.get() != null) {
-                            player.get().showPlayer(aPlayer.get());
+                            player.get().showPlayer(PVPArena.instance, aPlayer.get());
                         }
                     }
                 }
@@ -2115,13 +2026,34 @@ public void run() {
             Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
                 @Override
                 public void run() {
-                    player.setAllowFlight(false);
-                    player.setFlying(false);
+                    aPlayer.get().setAllowFlight(false);
+                    aPlayer.get().setFlying(false);
                 }
             }, 5L);
         }
     }
 
+    private void teleportPlayer(String place, final ArenaPlayer aPlayer, Location location) {
+        Player player = aPlayer.get();
+        player.teleport(location);
+        player.setNoDamageTicks(cfg.getInt(CFG.TIME_TELEPORTPROTECT) * 20);
+        if (place.contains("lounge")) {
+            getDebugger().i("setting TelePass later!");
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
+                @Override
+                public void run() {
+                    aPlayer.setTelePass(false);
+                    aPlayer.setTeleporting(false);
+                }
+            }, cfg.getInt(CFG.TIME_TELEPORTPROTECT) * 20);
+
+        } else {
+            getDebugger().i("setting TelePass now!");
+            aPlayer.setTelePass(false);
+            aPlayer.setTeleporting(false);
+        }
+    }
+
     /**
      * last resort to put a player into an arena (when no goal/module wants to)
      *
@@ -2138,7 +2070,6 @@ public boolean tryJoin(final Player player, final ArenaTeam team) {
 
         if ("ALL".equals(clear) || clear.contains(player.getGameMode().name())) {
             player.getInventory().clear();
-            player.updateInventory();
             ArenaPlayer.backupAndClearInventory(this, player);
             aPlayer.dump();
         }
@@ -2221,7 +2152,7 @@ && getClass(autoClass) == null) {
 
         for (final PASpawn spawn : spawns) {
             if (--pos < 0) {
-                tpPlayerToCoordName(player, spawn.getName());
+                this.tpPlayerToCoordName(aPlayer, spawn.getName());
                 break;
             }
         }
@@ -2396,34 +2327,32 @@ public void updateRounds() {
     }
 
     public void updateScoreboards() {
-        if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
-                @Override
-                public void run() {
-                    if (isFreeForAll()) {
-                        for (ArenaPlayer ap : getEveryone()) {
-                            int value = PACheck.handleGetLives(Arena.this, ap);
-                            if (value >= 0) {
-                                getSpecialScoreboard().getObjective("lives").getScore(ap.getName()).setScore(value);
-                            }
-                            Player player = ap.get();
-                            if (player != null && (player.getScoreboard() == null || !player.getScoreboard().equals(getSpecialScoreboard()))) {
-                                player.setScoreboard(getSpecialScoreboard());
-                            }
+        if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+                final Scoreboard currentScoreboard = this.getSpecialScoreboard();
+                if (this.isFreeForAll()) {
+                    for (ArenaPlayer ap : this.getEveryone()) {
+                        int value = PACheck.handleGetLives(this, ap);
+                        if (value >= 0 && ap.getStatus() != Status.WATCH) {
+                            currentScoreboard.getObjective("lives").getScore(ap.getName()).setScore(value);
                         }
-                    } else {
-                        for (ArenaTeam team : getTeams()) {
-                            for (ArenaPlayer ap : team.getTeamMembers()) {
-                                getSpecialScoreboard().getObjective("lives").getScore(team.getName()).setScore(
-                                        PACheck.handleGetLives(Arena.this, ap));
-                                break;
-                            }
+                        Player player = ap.get();
+                        if (player != null && !currentScoreboard.equals(player.getScoreboard())) {
+                            player.setScoreboard(currentScoreboard);
                         }
-                        for (ArenaPlayer ap : getEveryone()) {
-                            Player player = ap.get();
-                            if (player != null && (player.getScoreboard() == null || !player.getScoreboard().equals(getSpecialScoreboard()))) {
-                                player.setScoreboard(getSpecialScoreboard());
-                            }
+                    }
+                } else {
+                    for (ArenaTeam team : this.getTeams()) {
+                        team.getTeamMembers().stream().findFirst().ifPresent(randomTeamPlayer ->
+                            currentScoreboard.getObjective("lives")
+                                .getScore(team.getName())
+                                .setScore(PACheck.handleGetLives(this, randomTeamPlayer))
+                        );
+                    }
+                    for (ArenaPlayer ap : this.getEveryone()) {
+                        Player player = ap.get();
+                        if (player != null && !currentScoreboard.equals(player.getScoreboard())) {
+                            player.setScoreboard(currentScoreboard);
                         }
                     }
                 }
@@ -2432,72 +2361,57 @@ public void run() {
     }
 
     private void updateScoreboard(final Player player) {
-        if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+        if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+            Scoreboard currentScoreboard = this.getSpecialScoreboard();
             final ArenaPlayer ap = ArenaPlayer.parsePlayer(player.getName());
-            if (ap.getArenaTeam() == null) {
-                // a spectator, special case. Just update and do not add to the scores
-                if (player.getScoreboard() == null || !player.getScoreboard().equals(getSpecialScoreboard())) {
-                    player.setScoreboard(getSpecialScoreboard());
-                }
-                return;
-            }
-            if (isFreeForAll()) {
-                final Score score = getSpecialScoreboard().getObjective("lives").getScore(player.getName());
-                score.setScore(PACheck.handleGetLives(this, ArenaPlayer.parsePlayer(player.getName())));
-            } else {
-                getSpecialScoreboard().getObjective("lives").getScore(ap.getArenaTeam().getName()).setScore(PACheck.handleGetLives(this, ap));
-            }
-            if (player.getScoreboard() == null || !player.getScoreboard().equals(getSpecialScoreboard())) {
-                player.setScoreboard(getSpecialScoreboard());
+
+            // if player is a spectator, special case. Just update and do not add to the scores
+            if (ap.getArenaTeam() != null) {
+                currentScoreboard.getObjective("lives")
+                        .getScore(this.isFreeForAll() ? player.getName() : ap.getArenaTeam().getName())
+                        .setScore(PACheck.handleGetLives(this, ap));
             }
+
+            player.setScoreboard(currentScoreboard);
         }
     }
 
     public void updateScoreboardTeam(final Player player, final ArenaTeam oldTeam, final ArenaTeam newTeam) {
-        if (getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
-            final Scoreboard board = getSpecialScoreboard();
-            class RunLater implements Runnable {
+        if (this.getArenaConfig().getBoolean(CFG.USES_SCOREBOARD)) {
+            final Scoreboard board = this.getSpecialScoreboard();
 
-                @Override
-                public void run() {
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+                board.getTeam(oldTeam.getName()).removeEntry(player.getName());
 
-                    final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
-                    if (aPlayer.getArenaTeam() != null) {
-                        board.getTeam(oldTeam.getName()).removeEntry(player.getName());
+                Team sTeam = board.getTeams().stream()
+                        .filter(t -> t.getName().equals(newTeam.getName()))
+                        .findFirst()
+                        .orElseGet(() -> this.addNewTeam(board, newTeam));
+                sTeam.addEntry(player.getName());
 
-                        for (final Team sTeam : board.getTeams()) {
-                            if (sTeam.getName().equals(newTeam.getName())) {
-                                sTeam.addEntry(player.getName());
-                                return;
-                            }
-                        }
-                        final Team sTeam = board.registerNewTeam(newTeam.getName());
-                        sTeam.setPrefix(newTeam.getColor().toString());
-                        sTeam.addEntry(player.getName());
-                        sTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
-                    }
-                    updateScoreboard(player);
-                }
-
-            }
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RunLater(), 1L);
+                this.updateScoreboard(player);
+            }, 1L);
         } else {
-            Scoreboard board = getStandardScoreboard();
+            Scoreboard board = this.getStandardScoreboard();
             board.getTeam(oldTeam.getName()).removeEntry(player.getName());
 
-            for (final Team sTeam : board.getTeams()) {
-                if (sTeam.getName().equals(newTeam.getName())) {
-                    sTeam.addEntry(player.getName());
-                    return;
-                }
-            }
-            final Team sTeam = board.registerNewTeam(newTeam.getName());
-            sTeam.setPrefix(newTeam.getColor().toString());
-            sTeam.setCanSeeFriendlyInvisibles(!isFreeForAll());
+            Team sTeam = board.getTeams().stream()
+                    .filter(t -> t.getName().equals(newTeam.getName()))
+                    .findFirst()
+                    .orElseGet(() -> this.addNewTeam(board, newTeam));
             sTeam.addEntry(player.getName());
         }
     }
 
+    private Team addNewTeam(Scoreboard board, ArenaTeam newTeam) {
+        final Team sTeam = board.registerNewTeam(newTeam.getName());
+        sTeam.setPrefix(newTeam.getColor().toString());
+        sTeam.setSuffix(ChatColor.RESET.toString());
+        sTeam.setColor(newTeam.getColor());
+        sTeam.setCanSeeFriendlyInvisibles(!this.isFreeForAll());
+        return sTeam;
+    }
+
     public YamlConfiguration getLanguage() {
         return language;
     }
diff --git a/src/net/slipcor/pvparena/arena/ArenaClass.java b/src/net/slipcor/pvparena/arena/ArenaClass.java
index 9b6cd40b1..0a78c7397 100644
--- a/src/net/slipcor/pvparena/arena/ArenaClass.java
+++ b/src/net/slipcor/pvparena/arena/ArenaClass.java
@@ -3,22 +3,24 @@
 import net.slipcor.pvparena.PVPArena;
 import net.slipcor.pvparena.classes.PABlockLocation;
 import net.slipcor.pvparena.core.Debug;
-import net.slipcor.pvparena.core.StringParser;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
 import org.bukkit.block.Chest;
+import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.EntityType;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.PlayerInventory;
-import org.bukkit.inventory.meta.SpawnEggMeta;
-import org.bukkit.material.SpawnEgg;
 import org.bukkit.plugin.IllegalPluginAccessException;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.*;
 
+import static java.util.Arrays.asList;
+import static net.slipcor.pvparena.core.ItemStackUtils.getItemStacksFromConfig;
+
 /**
  * 
Arena Class class
*

@@ -39,50 +41,8 @@ public final class ArenaClass { private static final Map globals = new HashMap<>(); - // private statics: item definitions - private static final List ARMORS_TYPE = new LinkedList<>(); - private static final List HELMETS_TYPE = new LinkedList<>(); - private static final List CHESTPLATES_TYPE = new LinkedList<>(); - private static final List LEGGINGS_TYPE = new LinkedList<>(); - private static final List BOOTS_TYPE = new LinkedList<>(); - - // static filling of the items array - static { - HELMETS_TYPE.add(Material.LEATHER_HELMET); - HELMETS_TYPE.add(Material.GOLD_HELMET); - HELMETS_TYPE.add(Material.CHAINMAIL_HELMET); - HELMETS_TYPE.add(Material.IRON_HELMET); - HELMETS_TYPE.add(Material.DIAMOND_HELMET); - - HELMETS_TYPE.add(Material.WOOL); - HELMETS_TYPE.add(Material.PUMPKIN); - HELMETS_TYPE.add(Material.JACK_O_LANTERN); - HELMETS_TYPE.add(Material.SKULL_ITEM); - - CHESTPLATES_TYPE.add(Material.LEATHER_CHESTPLATE); - CHESTPLATES_TYPE.add(Material.GOLD_CHESTPLATE); - CHESTPLATES_TYPE.add(Material.CHAINMAIL_CHESTPLATE); - CHESTPLATES_TYPE.add(Material.IRON_CHESTPLATE); - CHESTPLATES_TYPE.add(Material.DIAMOND_CHESTPLATE); - CHESTPLATES_TYPE.add(Material.ELYTRA); - - LEGGINGS_TYPE.add(Material.LEATHER_LEGGINGS); - LEGGINGS_TYPE.add(Material.GOLD_LEGGINGS); - LEGGINGS_TYPE.add(Material.CHAINMAIL_LEGGINGS); - LEGGINGS_TYPE.add(Material.IRON_LEGGINGS); - LEGGINGS_TYPE.add(Material.DIAMOND_LEGGINGS); - - BOOTS_TYPE.add(Material.LEATHER_BOOTS); - BOOTS_TYPE.add(Material.GOLD_BOOTS); - BOOTS_TYPE.add(Material.CHAINMAIL_BOOTS); - BOOTS_TYPE.add(Material.IRON_BOOTS); - BOOTS_TYPE.add(Material.DIAMOND_BOOTS); - - ARMORS_TYPE.addAll(HELMETS_TYPE); - ARMORS_TYPE.addAll(CHESTPLATES_TYPE); - ARMORS_TYPE.addAll(LEGGINGS_TYPE); - ARMORS_TYPE.addAll(BOOTS_TYPE); - } + private static final List OTHER_HELMET_LIST = asList(Material.PUMPKIN, Material.JACK_O_LANTERN, Material.PLAYER_HEAD); + public static void addGlobalClasses() { globals.clear(); @@ -106,14 +66,20 @@ public static void addGlobalClasses() { } for (final String className : cfg.getConfigurationSection("classes").getKeys(false)) { - final String sItemList; + ItemStack[] items; + ItemStack offHand; + ItemStack[] armors; try { - sItemList = (String) cfg.getConfigurationSection("classes").get(className); + ConfigurationSection classesCfg = cfg.getConfigurationSection("classes").getConfigurationSection(className); + items = getItemStacksFromConfig(classesCfg.getList("items")); + offHand = getItemStacksFromConfig(classesCfg.getList("items"))[0]; + armors = getItemStacksFromConfig(classesCfg.getList("items")); } catch (final Exception e) { Bukkit.getLogger().severe( "[PVP Arena] Error while parsing class, skipping: " + className); + e.printStackTrace(); continue; } final String classChest; @@ -122,49 +88,12 @@ public static void addGlobalClasses() { PABlockLocation loc = new PABlockLocation(classChest); Chest c = (Chest) loc.toLocation().getBlock().getState(); ItemStack[] contents = c.getInventory().getContents(); - final ItemStack[] items = Arrays.copyOfRange(contents, 0, contents.length-5); - final ItemStack offHand = contents[contents.length-5]; - final ItemStack[] armors = Arrays.copyOfRange(contents, contents.length-4, contents.length); + items = Arrays.copyOfRange(contents, 0, contents.length-5); + offHand = contents[contents.length-5]; + armors = Arrays.copyOfRange(contents, contents.length-4, contents.length); globals.put(className, new ArenaClass(className, items, offHand, armors)); } catch (Exception e) { - final String[] sItems = sItemList.split(","); - final ItemStack[] items = new ItemStack[sItems.length]; - final ItemStack[] offhand = new ItemStack[1]; - final ItemStack[] armors = new ItemStack[4]; - - for (int i = 0; i < sItems.length; i++) { - - if (sItems[i].contains(">>!<<")) { - final String[] split = sItems[i].split(">>!<<"); - - final int id = Integer.parseInt(split[0]); - armors[id] = StringParser.getItemStackFromString(split[1]); - - if (armors[id] == null) { - PVPArena.instance.getLogger().warning( - "unrecognized armor item: " + split[1]); - } - - sItems[i] = "AIR"; - } else if (sItems[i].contains(">>O<<")) { - final String[] split = sItems[i].split(">>O<<"); - - final int id = Integer.parseInt(split[0]); - offhand[id] = StringParser.getItemStackFromString(split[1]); - - if (offhand[id] == null) { - PVPArena.instance.getLogger().warning( - "unrecognized armor item: " + split[1]); - } - } - - items[i] = StringParser.getItemStackFromString(sItems[i]); - if (items[i] == null) { - PVPArena.instance.getLogger().warning( - "unrecognized item: " + items[i]); - } - } - globals.put(className, new ArenaClass(className, items, offhand[0], armors)); + globals.put(className, new ArenaClass(className, items, offHand, armors)); } } } @@ -176,24 +105,24 @@ public static void addGlobalClasses(final Arena arena) { } public static void equip(final Player player, final ItemStack[] items) { - ItemStack last = items[items.length-1]; + int i = 0; for (final ItemStack item : items) { - if (ARMORS_TYPE.contains(item.getType())) { + if (isArmorItem(item.getType())) { equipArmor(item, player.getInventory()); } else { - if (last != null && last == item) { - player.getInventory().setItemInOffHand(last); + if (i == items.length - 1) { + player.getInventory().setItemInOffHand(item); continue; } - if (item.getType() == Material.MONSTER_EGG && item.hasItemMeta() && item.getItemMeta().hasDisplayName() && "SPAWN".equals(item.getItemMeta().getDisplayName())) { - final SpawnEggMeta egg = (SpawnEggMeta) item.getItemMeta(); + if (item.hasItemMeta() && item.getItemMeta().hasDisplayName() && "SPAWN".equals(item.getItemMeta().getDisplayName())) { + final String eggType = item.getType().name().replace("_SPAWN_EGG", ""); try { Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable(){ @Override public void run() { ArenaPlayer.parsePlayer(player.getName()).getArena().addEntity( - player, player.getWorld().spawnEntity(player.getLocation(), egg.getSpawnedType())); + player, player.getWorld().spawnEntity(player.getLocation(), EntityType.valueOf(eggType))); } }, 20L); } catch(final IllegalPluginAccessException e) { @@ -202,57 +131,80 @@ public void run() { } else { player.getInventory().addItem(item); } - debug.i("- " + StringParser.getStringFromItemStack(item), player); + } + i++; + } + } + + public static void equip(final Player player, final ItemStack[][] itemArray) { + try { + player.getInventory().setItemInOffHand(itemArray[1][0]); + } catch(ArrayIndexOutOfBoundsException e) { + player.getInventory().setItemInOffHand(new ItemStack(Material.AIR)); + } + + for(ItemStack itemStack : itemArray[2]) { + equipArmor(itemStack, player.getInventory()); + } + + for (final ItemStack item : itemArray[0]) { + if (item.getType().name().endsWith("_SPAWN_EGG")) { + final String eggType = item.getType().name().replace("_SPAWN_EGG", ""); + + try { + Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> + ArenaPlayer.parsePlayer(player.getName()).getArena().addEntity( + player, player.getWorld().spawnEntity(player.getLocation(), EntityType.valueOf(eggType))), 20L); + } catch(final IllegalPluginAccessException ignored) { + + } + } else { + player.getInventory().addItem(item); } } - player.updateInventory(); } public void equip(final Player player) { debug.i("Equipping player " + player.getName() + " with items!", player); - for (ItemStack item : armors) { + for (ItemStack item : this.armors) { if (item != null) { - debug.i("armor: "+StringParser.getStringFromItemStack(item)); equipArmor(item, player.getInventory()); } } - for (final ItemStack item : items) { + for (final ItemStack item : this.items) { if (item == null) { continue; } - if (ARMORS_TYPE.contains(item.getType())) { + if (isArmorItem(item.getType())) { equipArmor(item, player.getInventory()); } else { player.getInventory().addItem(item); - debug.i("- " + StringParser.getStringFromItemStack(item), player); } } - player.getInventory().setItemInOffHand(offHand); - player.updateInventory(); + player.getInventory().setItemInOffHand(this.offHand); } private static void equipArmor(final ItemStack stack, final PlayerInventory inv) { - debug.i("- " + StringParser.getStringFromItemStack(stack), (Player) inv.getHolder()); final Material type = stack.getType(); - if (HELMETS_TYPE.contains(type)) { + if (isHelmetItem(type)) { if (inv.getHelmet() != null && inv.getHelmet().getType() != Material.AIR) { inv.addItem(stack); } else { inv.setHelmet(stack); } - } else if (CHESTPLATES_TYPE.contains(type)) { + } else if (isChestplateItem(type)) { if (inv.getChestplate() != null && inv.getChestplate().getType() != Material.AIR) { inv.addItem(stack); } else { inv.setChestplate(stack); } - } else if (LEGGINGS_TYPE.contains(type)) { + } else if (isLeggingsItem(type)) { if (inv.getLeggings() != null && inv.getLeggings().getType() != Material.AIR) { inv.addItem(stack); } else { inv.setLeggings(stack); } - } else if (BOOTS_TYPE.contains(type)) { + } else if (isBootsItem(type)) { if (inv.getBoots() != null && inv.getBoots().getType() != Material.AIR) { inv.addItem(stack); } else { @@ -261,32 +213,43 @@ private static void equipArmor(final ItemStack stack, final PlayerInventory inv) } } - /** - * Backwards compatible offhand-less implementation of the constructor - * - * @deprecated use {@link #ArenaClass(String, ItemStack[], ItemStack, ItemStack[])} } instead. - */ - @Deprecated - public ArenaClass(final String className, final ItemStack[] classItems, final ItemStack[] armors) { - this(className, classItems, null, armors); - } - public ArenaClass(final String className, final ItemStack[] classItems, final ItemStack offHand, final ItemStack[] armors) { - name = className; + this.name = className; this.offHand = offHand; - items = classItems.clone(); + this.items = classItems.clone(); this.armors = armors.clone(); } public String getName() { - return name; + return this.name; } public ItemStack[] getArmors() { - return armors.clone(); + return this.armors.clone(); } public ItemStack[] getItems() { - return items.clone(); + return this.items.clone(); + } + + private static boolean isHelmetItem(Material material) { + return material.name().endsWith("_HELMET") || material.name().endsWith("_WOOL") || + OTHER_HELMET_LIST.contains(material); + } + + private static boolean isChestplateItem(Material material) { + return material.name().endsWith("_CHESTPLATE") || material == Material.ELYTRA; + } + + private static boolean isLeggingsItem(Material material) { + return material.name().endsWith("_LEGGINGS"); + } + + private static boolean isBootsItem(Material material) { + return material.name().endsWith("_BOOTS"); + } + + private static boolean isArmorItem(Material material) { + return isBootsItem(material) || isLeggingsItem(material) || isChestplateItem(material) || isHelmetItem(material); } -} \ No newline at end of file +} diff --git a/src/net/slipcor/pvparena/arena/ArenaPlayer.java b/src/net/slipcor/pvparena/arena/ArenaPlayer.java index cd1fa5f60..483ba0908 100644 --- a/src/net/slipcor/pvparena/arena/ArenaPlayer.java +++ b/src/net/slipcor/pvparena/arena/ArenaPlayer.java @@ -4,16 +4,16 @@ import net.slipcor.pvparena.classes.PABlockLocation; import net.slipcor.pvparena.classes.PALocation; import net.slipcor.pvparena.classes.PAStatMap; +import net.slipcor.pvparena.core.ColorUtils; import net.slipcor.pvparena.core.Config; import net.slipcor.pvparena.core.Config.CFG; import net.slipcor.pvparena.core.Debug; -import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.events.PAPlayerClassChangeEvent; import net.slipcor.pvparena.loadables.ArenaModuleManager; import net.slipcor.pvparena.managers.ArenaManager; import net.slipcor.pvparena.managers.InventoryManager; import net.slipcor.pvparena.managers.SpawnManager; -import net.slipcor.pvparena.managers.StatisticsManager.type; +import net.slipcor.pvparena.managers.StatisticsManager.Type; import org.bukkit.*; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.*; @@ -24,11 +24,12 @@ import org.bukkit.permissions.PermissionAttachment; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.scoreboard.Scoreboard; -import org.bukkit.scoreboard.Team; import java.io.File; import java.util.*; +import static java.util.Optional.ofNullable; + /** *

  * Arena Player class
@@ -64,7 +65,7 @@ public class ArenaPlayer {
     private final Map statistics = new HashMap<>();
 
     private Scoreboard backupBoard;
-    private Team backupBoardTeam;
+    private String backupBoardTeam;
 
     /**
      * Status
@@ -101,6 +102,7 @@ public enum Status {
      */
     public enum PlayerPrevention {
         BREAK, PLACE, TNT, TNTBREAK, DROP, INVENTORY, PICKUP, CRAFT;
+
         public static boolean has(int value, PlayerPrevention s) {
             return (((int) Math.pow(2, s.ordinal()) & value) > 0);
         }
@@ -110,28 +112,11 @@ public static boolean has(int value, PlayerPrevention s) {
     private final PABlockLocation[] selection = new PABlockLocation[2];
 
     private ArenaPlayer(final String playerName) {
-        name = playerName;
-
-        totalPlayers.put(name, this);
-    }
-
-    private ArenaPlayer(final Player player, final Arena arena) {
-        name = player.getName();
-        this.arena = arena;
-
-        totalPlayers.put(name, this);
-    }
-
-    public static int countPlayers() {
-        return totalPlayers.size();
+        this.name = playerName;
     }
 
     public static Set getAllArenaPlayers() {
-        final Set players = new HashSet<>();
-        for (final ArenaPlayer ap : totalPlayers.values()) {
-            players.add(ap);
-        }
-        return players;
+        return new HashSet<>(totalPlayers.values());
     }
 
     public boolean getFlyState() {
@@ -184,7 +169,8 @@ public static Player getLastDamagingPlayer(final Event eEvent, final Player dama
             }
         }
         debug.i("last damaging player is null", damagee);
-        debug.i("last damaging event: " + eEvent.getEventName(), damagee);
+        debug.i("last damaging event: " + ofNullable(eEvent).map(Event::getEventName)
+                .orElse("unknown cause"), damagee);
         return null;
     }
 
@@ -207,58 +193,47 @@ public static void givePlayerFightItems(final Arena arena, final Player player)
 
         if (arena.getArenaConfig().getBoolean(CFG.USES_WOOLHEAD)) {
             final ArenaTeam aTeam = aPlayer.getArenaTeam();
-            final String color = aTeam.getColor().name();
+            final ChatColor color = aTeam.getColor();
             arena.getDebugger().i("forcing woolhead: " + aTeam.getName() + '/'
-                    + color, player);
+                    + color.name(), player);
             player.getInventory().setHelmet(
-                    new ItemStack(Material.WOOL, 1, StringParser
-                            .getColorDataFromENUM(color)));
+                    new ItemStack(ColorUtils.getWoolMaterialFromChatColor(color)));
         }
     }
 
-    public static void initiate() {
-        debug.i("creating offline arena players");
-
-        if (!PVPArena.instance.getConfig().getBoolean("stats")) {
-            return;
-        }
-
-        final YamlConfiguration cfg = new YamlConfiguration();
-        try {
-            cfg.load(PVPArena.instance.getDataFolder() + "/players.yml");
-
-            final Set arenas = cfg.getKeys(false);
-
-            for (final String arenaname : arenas) {
-
-                final Set players = cfg.getConfigurationSection(arenaname).getKeys(false);
-                for (final String player : players) {
-                    totalPlayers.put(player, ArenaPlayer.parsePlayer(player));
-                }
+    /**
+     * get an ArenaPlayer from a player name
+     *
+     * @param name the playername to use
+     * @return an ArenaPlayer instance belonging to that player
+     */
+    public static ArenaPlayer parsePlayer(final String name) {
+        synchronized (ArenaPlayer.class) {
+            Player player = Bukkit.getPlayerExact(name);
 
+            // Offline player or NPC
+            if (player == null) {
+                return new ArenaPlayer(name);
             }
 
-        } catch (final Exception e) {
-            e.printStackTrace();
+            if (!totalPlayers.containsKey(name)) {
+                ArenaPlayer ap = new ArenaPlayer(player.getName());
+                totalPlayers.putIfAbsent(name, ap);
+            }
+            return totalPlayers.get(name);
         }
     }
 
     /**
-     * get an ArenaPlayer from a player name
+     * add an ArenaPlayer (used to load statistics)
      *
      * @param name the playername to use
      * @return an ArenaPlayer instance belonging to that player
      */
-    public static ArenaPlayer parsePlayer(final String name) {
+    public static ArenaPlayer addPlayer(final String name) {
         synchronized (ArenaPlayer.class) {
-            if (totalPlayers.get(name) == null) {
-                if (Bukkit.getPlayerExact(name) == null) {
-                    totalPlayers.put(name, new ArenaPlayer(name));
-                } else {
-                    totalPlayers.put(name,
-                            new ArenaPlayer(Bukkit.getPlayerExact(name), null));
-                }
-            }
+            ArenaPlayer aPlayer = new ArenaPlayer(name);
+            totalPlayers.putIfAbsent(name, aPlayer);
             return totalPlayers.get(name);
         }
     }
@@ -291,8 +266,9 @@ public static void reloadInventory(final Arena arena, final Player player, final
 
         final ArenaPlayer aPlayer = parsePlayer(player.getName());
 
-        if (!"none".equals(arena.getArenaConfig().getString(CFG.ITEMS_TAKEOUTOFGAME))) {
-            final ItemStack[] items = StringParser.getItemStacksFromString(arena.getArenaConfig().getString(CFG.ITEMS_TAKEOUTOFGAME));
+        if (arena.getArenaConfig().getYamlConfiguration().get(CFG.ITEMS_TAKEOUTOFGAME.getNode()) != null) {
+            final ItemStack[] items =
+                    arena.getArenaConfig().getItems(CFG.ITEMS_TAKEOUTOFGAME);
 
             final List allowedMats = new ArrayList<>();
 
@@ -338,20 +314,22 @@ public void run() {
 
         if (instant) {
 
-            debug.i("adding " + StringParser.getStringFromItemStacks(aPlayer.savedInventory), player);
+            debug.i("adding saved inventory", player);
             player.getInventory().setContents(aPlayer.savedInventory);
         } else {
             class GiveLater implements Runnable {
                 final ItemStack[] inv;
+
                 GiveLater(final ItemStack[] inv) {
                     this.inv = inv.clone();
-                    }
+                }
+
                 @Override
                 public void run() {
-                    debug.i("adding " + StringParser.getStringFromItemStacks(inv),
+                    debug.i("adding saved inventory",
                             player);
                     player.getInventory().setContents(inv);
-                    }
+                }
             }
             final GiveLater gl = new GiveLater(aPlayer.savedInventory);
             try {
@@ -363,18 +341,18 @@ public void run() {
     }
 
     public void addDeath() {
-        getStatistics(arena).incStat(type.DEATHS);
+        getStatistics(arena).incStat(Type.DEATHS);
     }
 
     public void addKill() {
-        getStatistics(arena).incStat(type.KILLS);
+        getStatistics(arena).incStat(Type.KILLS);
     }
 
     public void addLosses() {
-        getStatistics(arena).incStat(type.LOSSES);
+        getStatistics(arena).incStat(Type.LOSSES);
     }
 
-    public void addStatistic(final String arenaName, final type type,
+    public void addStatistic(final String arenaName, final Type type,
                              final int value) {
         if (!statistics.containsKey(arenaName)) {
             statistics.put(arenaName, new PAStatMap());
@@ -384,7 +362,7 @@ public void addStatistic(final String arenaName, final type type,
     }
 
     public void addWins() {
-        getStatistics(arena).incStat(type.WINS);
+        getStatistics(arena).incStat(Type.WINS);
     }
 
     private void clearDump() {
@@ -435,9 +413,6 @@ public void debugPrint() {
                 name);
         debug.i("location: " + location, name);
         debug.i("status: " + status.name(), name);
-        debug.i("savedInventory: "
-                        + StringParser.getStringFromItemStacks(savedInventory),
-                name);
         debug.i("tempPermissions:", name);
         for (final PermissionAttachment pa : tempPermissions) {
             debug.i("> " + pa, name);
@@ -499,6 +474,7 @@ public Arena getArena() {
     public ArenaClass getArenaClass() {
         return aClass;
     }
+
     public ArenaClass getNextArenaClass() {
         return naClass;
     }
@@ -519,7 +495,7 @@ public Scoreboard getBackupScoreboard() {
         return backupBoard;
     }
 
-    public Team getBackupScoreboardTeam() {
+    public String getBackupScoreboardTeam() {
         return backupBoardTeam;
     }
 
@@ -592,7 +568,7 @@ public Set getTempPermissions() {
         return tempPermissions;
     }
 
-    public int getTotalStatistics(final type statType) {
+    public int getTotalStatistics(final Type statType) {
         int sum = 0;
 
         for (final PAStatMap stat : statistics.values()) {
@@ -618,6 +594,10 @@ public boolean isPublicChatting() {
         return publicChatting;
     }
 
+    public boolean hasCustomClass() {
+        return this.getArenaClass() != null && "custom".equalsIgnoreCase(this.getArenaClass().getName());
+    }
+
     public void readDump() {
         debug.i("reading dump: " + name, name);
         debugPrint();
@@ -676,34 +656,34 @@ public void reset() {
                 if (arena != null) {
                     final String arenaName = arena.getName();
                     cfg.set(arenaName + '.' + name + ".losses", getStatistics()
-                            .getStat(type.LOSSES)
-                            + getTotalStatistics(type.LOSSES));
+                            .getStat(Type.LOSSES)
+                            + getTotalStatistics(Type.LOSSES));
                     cfg.set(arenaName + '.' + name + ".wins",
                             getStatistics()
-                                    .getStat(type.WINS)
-                                    + getTotalStatistics(type.WINS));
+                                    .getStat(Type.WINS)
+                                    + getTotalStatistics(Type.WINS));
                     cfg.set(arenaName + '.' + name + ".kills",
                             getStatistics().getStat(
-                                    type.KILLS)
-                                    + getTotalStatistics(type.KILLS));
+                                    Type.KILLS)
+                                    + getTotalStatistics(Type.KILLS));
                     cfg.set(arenaName + '.' + name + ".deaths", getStatistics()
-                            .getStat(type.DEATHS)
-                            + getTotalStatistics(type.DEATHS));
+                            .getStat(Type.DEATHS)
+                            + getTotalStatistics(Type.DEATHS));
                     cfg.set(arenaName + '.' + name + ".damage", getStatistics()
-                            .getStat(type.DAMAGE)
-                            + getTotalStatistics(type.DAMAGE));
+                            .getStat(Type.DAMAGE)
+                            + getTotalStatistics(Type.DAMAGE));
                     cfg.set(arenaName + '.' + name + ".maxdamage",
                             getStatistics().getStat(
-                                    type.MAXDAMAGE)
-                                    + getTotalStatistics(type.MAXDAMAGE));
+                                    Type.MAXDAMAGE)
+                                    + getTotalStatistics(Type.MAXDAMAGE));
                     cfg.set(arenaName + '.' + name + ".damagetake",
                             getStatistics().getStat(
-                                    type.DAMAGETAKE)
-                                    + getTotalStatistics(type.DAMAGETAKE));
+                                    Type.DAMAGETAKE)
+                                    + getTotalStatistics(Type.DAMAGETAKE));
                     cfg.set(arenaName + '.' + name + ".maxdamagetake",
                             getStatistics().getStat(
-                                    type.MAXDAMAGETAKE)
-                                    + getTotalStatistics(type.MAXDAMAGETAKE));
+                                    Type.MAXDAMAGETAKE)
+                                    + getTotalStatistics(Type.MAXDAMAGETAKE));
                 }
 
                 cfg.save(file);
@@ -767,11 +747,11 @@ public final void setArena(final Arena arena) {
      * @param aClass the arena class to set
      */
     public void setArenaClass(final ArenaClass aClass) {
-        final PAPlayerClassChangeEvent event = new PAPlayerClassChangeEvent(arena, get(), aClass);
+        final PAPlayerClassChangeEvent event = new PAPlayerClassChangeEvent(this.arena, this.get(), aClass);
         Bukkit.getServer().getPluginManager().callEvent(event);
         this.aClass = event.getArenaClass();
-        if (arena != null) {
-            ArenaModuleManager.parseClassChange(arena, get(), this.aClass);
+        if (this.arena != null && this.getStatus() != Status.NULL) {
+            ArenaModuleManager.parseClassChange(this.arena, this.get(), this.aClass);
         }
     }
 
@@ -797,8 +777,8 @@ public void setBackupScoreboard(Scoreboard board) {
         backupBoard = board;
     }
 
-    public void setBackupScoreboardTeam(Team team) {
-        backupBoardTeam = team;
+    public void setBackupScoreboardTeam(String sbTeamName) {
+        this.backupBoardTeam = sbTeamName;
     }
 
     public void setMayDropInventory(boolean value) {
@@ -833,7 +813,7 @@ public void setSelection(final Location loc, final boolean second) {
         }
     }
 
-    public void setStatistic(final String arenaName, final type type,
+    public void setStatistic(final String arenaName, final Type type,
                              final int value) {
         if (!statistics.containsKey(arenaName)) {
             statistics.put(arenaName, new PAStatMap());
@@ -855,7 +835,7 @@ public void setStatus(final Status status) {
      */
     public void setTelePass(final boolean canTeleport) {
         if (arena != null) {
-            arena.getDebugger().i("TelePass := "+canTeleport);
+            arena.getDebugger().i("TelePass := " + canTeleport);
         }
         telePass = canTeleport;
     }
@@ -868,8 +848,7 @@ public void showBloodParticles() {
         Player player = get();
         player.getLocation()
                 .getWorld()
-                .playEffect(player.getEyeLocation(),
-                        Effect.STEP_SOUND, Material.NETHER_WART_BLOCK.getId());
+                .playEffect(player.getEyeLocation(), Effect.STEP_SOUND, Material.NETHER_WART_BLOCK);
 
     }
 
@@ -877,8 +856,7 @@ public void showBloodParticles() {
     public String toString() {
         final ArenaTeam team = getArenaTeam();
 
-        return team == null ? name : team.getColorCodeString() + name
-                + ChatColor.RESET;
+        return team == null ? name : team.getColorCodeString() + name + ChatColor.RESET;
     }
 
     public void unsetSelection() {
diff --git a/src/net/slipcor/pvparena/arena/ArenaTeam.java b/src/net/slipcor/pvparena/arena/ArenaTeam.java
index d2c62ce4f..d5d48c1d3 100644
--- a/src/net/slipcor/pvparena/arena/ArenaTeam.java
+++ b/src/net/slipcor/pvparena/arena/ArenaTeam.java
@@ -1,8 +1,8 @@
 package net.slipcor.pvparena.arena;
 
 import net.slipcor.pvparena.arena.ArenaPlayer.Status;
+import net.slipcor.pvparena.core.ColorUtils;
 import net.slipcor.pvparena.core.Debug;
-import net.slipcor.pvparena.core.StringParser;
 import org.bukkit.ChatColor;
 import org.bukkit.entity.Player;
 
@@ -34,7 +34,7 @@ public class ArenaTeam {
      */
     public ArenaTeam(final String name, final String color) {
         players = new HashSet<>();
-        this.color = StringParser.getChatColorFromWoolEnum(color);
+        this.color = ColorUtils.getChatColorFromDyeColor(color);
         this.name = name;
     }
 
@@ -125,4 +125,12 @@ public boolean isEveryoneReady() {
     public void remove(final ArenaPlayer player) {
         players.remove(player);
     }
-}
\ No newline at end of file
+
+    @Override
+    public String toString() {
+        return "ArenaTeam{" +
+                "color=" + this.color +
+                ", name='" + this.name + '\'' +
+                '}';
+    }
+}
diff --git a/src/net/slipcor/pvparena/arena/PlayerState.java b/src/net/slipcor/pvparena/arena/PlayerState.java
index 8b6929556..f9e92494e 100644
--- a/src/net/slipcor/pvparena/arena/PlayerState.java
+++ b/src/net/slipcor/pvparena/arena/PlayerState.java
@@ -105,7 +105,7 @@ public static void fullReset(final Arena arena, final Player player) {
         }
 
         if (arena.getArenaConfig().getInt(CFG.PLAYER_MAXHEALTH) > 0) {
-            player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(arena.getArenaConfig().getInt(CFG.PLAYER_MAXHEALTH));
+             player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(arena.getArenaConfig().getInt(CFG.PLAYER_MAXHEALTH));
         }
 
         if (iHealth > player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue()) {
@@ -115,12 +115,9 @@ public static void fullReset(final Arena arena, final Player player) {
         }
         player.setFireTicks(0);
         try {
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
-                @Override
-                public void run() {
-                    if (player.getFireTicks() > 0) {
-                        player.setFireTicks(0);
-                    }
+            Bukkit.getScheduler().runTaskLater(PVPArena.instance, () -> {
+                if (player.getFireTicks() > 0) {
+                    player.setFireTicks(0);
                 }
             }, 5L);
         } catch (Exception e) {
@@ -129,8 +126,7 @@ public void run() {
         player.setVelocity(new Vector());
         player.setFoodLevel(arena.getArenaConfig().getInt(CFG.PLAYER_FOODLEVEL));
         player.setSaturation(arena.getArenaConfig().getInt(CFG.PLAYER_SATURATION));
-        player.setExhaustion((float) arena.getArenaConfig().getDouble(
-                CFG.PLAYER_EXHAUSTION));
+        player.setExhaustion((float) arena.getArenaConfig().getDouble(CFG.PLAYER_EXHAUSTION));
         player.setLevel(0);
         player.setExp(0);
         if (arena.getArenaConfig().getInt(CFG.GENERAL_GAMEMODE) > -1) {
@@ -242,7 +238,7 @@ public void run() {
      * @param player the player to set
      * @param value  the health value
      */
-    public static void playersetHealth(final Player player, final int value) {
+    public static void playersetHealth(final Player player, final double value) {
         debug.i("setting health to " + value + "/20", player);
         if (Bukkit.getServer().getPluginManager().getPlugin("Heroes") == null) {
             player.setHealth(value);
@@ -250,8 +246,7 @@ public static void playersetHealth(final Player player, final int value) {
         final double current = player.getHealth();
         final double regain = value - current;
 
-        final EntityRegainHealthEvent event = new EntityRegainHealthEvent(player, regain,
-                RegainReason.CUSTOM);
+        final EntityRegainHealthEvent event = new EntityRegainHealthEvent(player, regain, RegainReason.CUSTOM);
         Bukkit.getPluginManager().callEvent(event);
     }
 
diff --git a/src/net/slipcor/pvparena/classes/PABlock.java b/src/net/slipcor/pvparena/classes/PABlock.java
index 3878c176d..e41259fe7 100644
--- a/src/net/slipcor/pvparena/classes/PABlock.java
+++ b/src/net/slipcor/pvparena/classes/PABlock.java
@@ -5,24 +5,24 @@ public class PABlock {
     private final String name;
 
     public PABlock(final PABlockLocation loc, final String string) {
-        location = loc;
-        name = string;
+        this.location = loc;
+        this.name = string;
     }
 
     @Override
     public boolean equals(final Object o) {
         if (o instanceof PABlock) {
             final PABlock other = (PABlock) o;
-            return name.equals(other.name) && location.equals(other.location);
+            return this.name.equals(other.name) && this.location.equals(other.location);
         }
         return false;
     }
 
     public PABlockLocation getLocation() {
-        return location;
+        return this.location;
     }
 
     public String getName() {
-        return name;
+        return this.name;
     }
 }
diff --git a/src/net/slipcor/pvparena/classes/PABlockLocation.java b/src/net/slipcor/pvparena/classes/PABlockLocation.java
index 3cf916ea8..75b40a592 100644
--- a/src/net/slipcor/pvparena/classes/PABlockLocation.java
+++ b/src/net/slipcor/pvparena/classes/PABlockLocation.java
@@ -30,30 +30,30 @@ public PABlockLocation(final String world, final int x, final int y, final int z
 
     public PABlockLocation(final String value) {
         String[] split = value.split(":");
-        world = split[0];
+        this.world = split[0];
 
         String[] ints = split[1].split(",");
 
-        x = Integer.parseInt(ints[0]);
-        y = Integer.parseInt(ints[1]);
-        z = Integer.parseInt(ints[2]);
+        this.x = Integer.parseInt(ints[0]);
+        this.y = Integer.parseInt(ints[1]);
+        this.z = Integer.parseInt(ints[2]);
     }
 
     public PABlockLocation(final Location bukkitLocation) {
-        world = bukkitLocation.getWorld().getName();
-        x = bukkitLocation.getBlockX();
-        y = bukkitLocation.getBlockY();
-        z = bukkitLocation.getBlockZ();
+        this.world = bukkitLocation.getWorld().getName();
+        this.x = bukkitLocation.getBlockX();
+        this.y = bukkitLocation.getBlockY();
+        this.z = bukkitLocation.getBlockZ();
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (world == null ? 0 : world.hashCode());
-        result = prime * result + x;
-        result = prime * result + y;
-        result = prime * result + z;
+        result = prime * result + (this.world == null ? 0 : this.world.hashCode());
+        result = prime * result + this.x;
+        result = prime * result + this.y;
+        result = prime * result + this.z;
         return result;
     }
 
@@ -65,24 +65,24 @@ public boolean equals(final Object obj) {
         if (obj == null) {
             return false;
         }
-        if (getClass() != obj.getClass()) {
+        if (this.getClass() != obj.getClass()) {
             return false;
         }
         final PABlockLocation other = (PABlockLocation) obj;
-        if (world == null) {
+        if (this.world == null) {
             if (other.world != null) {
                 return false;
             }
-        } else if (!world.equals(other.world)) {
+        } else if (!this.world.equals(other.world)) {
             return false;
         }
-        if (x != other.x) {
+        if (this.x != other.x) {
             return false;
         }
-        if (y != other.y) {
+        if (this.y != other.y) {
             return false;
         }
-        return z == other.z;
+        return this.z == other.z;
     }
 
     public double getDistance(final PABlockLocation otherLocation) {
@@ -90,14 +90,14 @@ public double getDistance(final PABlockLocation otherLocation) {
             throw new IllegalArgumentException(
                     "Cannot measure distance to a null location");
         }
-        if (!otherLocation.world.equals(world)) {
+        if (!otherLocation.world.equals(this.world)) {
             throw new IllegalArgumentException(
-                    "Cannot measure distance between " + world + " and "
+                    "Cannot measure distance between " + this.world + " and "
                             + otherLocation.world);
         }
 
-        return Math.sqrt(Math.pow(x - otherLocation.x, 2.0D)
-                + Math.pow(y - otherLocation.y, 2.0D) + Math.pow(z - otherLocation.z, 2.0D));
+        return Math.sqrt(Math.pow(this.x - otherLocation.x, 2.0D)
+                + Math.pow(this.y - otherLocation.y, 2.0D) + Math.pow(this.z - otherLocation.z, 2.0D));
     }
 
     public double getDistanceSquared(final PABlockLocation otherLocation) {
@@ -105,77 +105,77 @@ public double getDistanceSquared(final PABlockLocation otherLocation) {
             throw new IllegalArgumentException(
                     "Cannot measure distance to a null location");
         }
-        if (!otherLocation.world.equals(world)) {
+        if (!otherLocation.world.equals(this.world)) {
             throw new IllegalArgumentException(
-                    "Cannot measure distance between " + world + " and "
+                    "Cannot measure distance between " + this.world + " and "
                             + otherLocation.world);
         }
 
-        return Math.pow(x - otherLocation.x, 2.0D)
-                + Math.pow(y - otherLocation.y, 2.0D) + Math.pow(z - otherLocation.z, 2.0D);
+        return Math.pow(this.x - otherLocation.x, 2.0D)
+                + Math.pow(this.y - otherLocation.y, 2.0D) + Math.pow(this.z - otherLocation.z, 2.0D);
     }
 
     public PABlockLocation getMidpoint(final PABlockLocation location) {
-        return new PABlockLocation(world, (x + location.x) / 2, (y + location.y) / 2,
-                (z + location.z) / 2);
+        return new PABlockLocation(this.world, (this.x + location.x) / 2, (this.y + location.y) / 2,
+                (this.z + location.z) / 2);
     }
 
     public String getWorldName() {
-        return world;
+        return this.world;
     }
 
     public int getX() {
-        return x;
+        return this.x;
     }
 
     public int getY() {
-        return y;
+        return this.y;
     }
 
     public int getZ() {
-        return z;
+        return this.z;
     }
 
     public boolean isInAABB(final PABlockLocation min, final PABlockLocation max) {
-        if (x < min.x || x > max.x) {
+        if (this.x < min.x || this.x > max.x) {
             return false;
         }
-        if (y < min.y || y > max.y) {
+        if (this.y < min.y || this.y > max.y) {
             return false;
         }
-        return !(z < min.z || z > max.z);
+        return !(this.z < min.z || this.z > max.z);
     }
 
     public PABlockLocation pointTo(final PABlockLocation dest, final Double length) {
-        final Vector source = new Vector(x, y, z);
+        final Vector source = new Vector(this.x, this.y, this.z);
         final Vector destination = new Vector(dest.x, dest.y, dest.z);
 
         Vector goal = source.subtract(destination);
 
         goal = goal.normalize().multiply(length);
 
-        return new PABlockLocation(world, x + x + goal.getBlockX(), y
-                + goal.getBlockY(), z + goal.getBlockZ());
+        return new PABlockLocation(this.world, this.x + this.x + goal.getBlockX(), this.y
+                + goal.getBlockY(), this.z + goal.getBlockZ());
     }
 
     public void setX(final int value) {
-        x = value;
+        this.x = value;
     }
 
     public void setY(final int value) {
-        y = value;
+        this.y = value;
     }
 
     public void setZ(final int value) {
-        z = value;
+        this.z = value;
     }
 
     public Location toLocation() {
-        return new Location(Bukkit.getWorld(world), x, y, z);
+        return new Location(Bukkit.getWorld(this.world), this.x, this.y, this.z);
     }
 
     @Override
     public String toString() {
-        return world + ':' + x + ',' + y + ',' + z;
+        return this.world + ':' + this.x + ',' + this.y + ',' + this.z;
     }
 }
diff --git a/src/net/slipcor/pvparena/classes/PACheck.java b/src/net/slipcor/pvparena/classes/PACheck.java
index 925505d48..2cba17dd8 100644
--- a/src/net/slipcor/pvparena/classes/PACheck.java
+++ b/src/net/slipcor/pvparena/classes/PACheck.java
@@ -11,7 +11,6 @@
 import net.slipcor.pvparena.core.Debug;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAJoinEvent;
 import net.slipcor.pvparena.events.PAStartEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
@@ -334,19 +333,20 @@ public static boolean handleJoin(final Arena arena,
 
         final ArenaTeam team;
 
-        if (args.length < 1 || arena.getTeam(args[0]) == null) {
+        if (args.length < 1) {
             // usage: /pa {arenaname} join | join an arena
 
             team = arena.getTeam(TeamManager.calcFreeTeam(arena));
+        } else if(arena.getTeam(args[0]) == null) {
+            arena.msg(sender, Language.parse(arena, MSG.ERROR_TEAMNOTFOUND, args[0]));
+            return false;
         } else {
             ArenaTeam aTeam = arena.getTeam(args[0]);
 
             int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
             int maxTeamPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXTEAMPLAYERS);
 
-            if (aTeam == null) {
-                team = aTeam;
-            } else if (maxPlayers > 0 && arena.getFighters().size() > maxPlayers) {
+            if (maxPlayers > 0 && arena.getFighters().size() > maxPlayers) {
                 arena.msg(sender, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
                 return false;
             } else if (maxTeamPlayers > 0 && aTeam.getTeamMembers().size() > maxTeamPlayers) {
@@ -357,11 +357,6 @@ public static boolean handleJoin(final Arena arena,
             }
         }
 
-        if (team == null && args.length > 0) {
-            arena.msg(sender,
-                    Language.parse(arena, MSG.ERROR_TEAMNOTFOUND, args[0]));
-            return false;
-        }
         if (team == null) {
             arena.msg(sender, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
             return false;
@@ -517,7 +512,7 @@ public static void handlePlayerDeath(final Arena arena,
         StatisticsManager.kill(arena, player.getKiller(), player, doesRespawn);
         if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES) ||
                 arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGESCUSTOM)) {
-            event.setDeathMessage(null);
+            event.setDeathMessage("");
         }
 
         if (player.getKiller() != null) {
@@ -532,15 +527,13 @@ public static void handlePlayerDeath(final Arena arena,
                 InventoryManager.clearInventory(player.getKiller());
                 ArenaPlayer.parsePlayer(player.getKiller().getName()).getArenaClass().equip(player.getKiller());
             }
-            if (!arena.getArenaConfig().getString(CFG.PLAYER_ITEMSONKILL).equals("none")) {
-                String definition = arena.getArenaConfig().getString(CFG.PLAYER_ITEMSONKILL);
-                ItemStack[] items = StringParser.getItemStacksFromString(definition);
+            if (arena.getArenaConfig().getItems(CFG.PLAYER_ITEMSONKILL) != null) {
+                ItemStack[] items = arena.getArenaConfig().getItems(CFG.PLAYER_ITEMSONKILL);
                 for (ItemStack item : items) {
                     if (item != null) {
                         player.getKiller().getInventory().addItem(item.clone());
                     }
                 }
-                player.getKiller().updateInventory();
             }
             if (arena.getArenaConfig().getBoolean(CFG.USES_TELEPORTONKILL)) {
                 SpawnManager.respawn(arena, ArenaPlayer.parsePlayer(player.getKiller().getName()), null);
diff --git a/src/net/slipcor/pvparena/classes/PAClaimBar.java b/src/net/slipcor/pvparena/classes/PAClaimBar.java
index 8b26a240f..49378890c 100644
--- a/src/net/slipcor/pvparena/classes/PAClaimBar.java
+++ b/src/net/slipcor/pvparena/classes/PAClaimBar.java
@@ -2,7 +2,6 @@
 
 import net.slipcor.pvparena.PVPArena;
 import net.slipcor.pvparena.arena.Arena;
-import net.slipcor.pvparena.arena.ArenaPlayer;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.Location;
diff --git a/src/net/slipcor/pvparena/classes/PAStatMap.java b/src/net/slipcor/pvparena/classes/PAStatMap.java
index 81a8b9827..070af56ae 100644
--- a/src/net/slipcor/pvparena/classes/PAStatMap.java
+++ b/src/net/slipcor/pvparena/classes/PAStatMap.java
@@ -15,29 +15,29 @@
  */
 
 public class PAStatMap {
-    private final Map map = new HashMap<>();
+    private final Map map = new HashMap<>();
 
-    public void decStat(final StatisticsManager.type type) {
+    public void decStat(final StatisticsManager.Type type) {
         decStat(type, 1);
     }
 
-    public void decStat(final StatisticsManager.type type, final int value) {
+    public void decStat(final StatisticsManager.Type type, final int value) {
         map.put(type, getStat(type) - value);
     }
 
-    public int getStat(final StatisticsManager.type type) {
+    public int getStat(final StatisticsManager.Type type) {
         return map.containsKey(type) ? map.get(type) : 0;
     }
 
-    public void incStat(final StatisticsManager.type type) {
+    public void incStat(final StatisticsManager.Type type) {
         incStat(type, 1);
     }
 
-    public void incStat(final StatisticsManager.type type, final int value) {
+    public void incStat(final StatisticsManager.Type type, final int value) {
         map.put(type, getStat(type) + value);
     }
 
-    public void setStat(final StatisticsManager.type type, final int value) {
+    public void setStat(final StatisticsManager.Type type, final int value) {
         map.put(type, value);
     }
 }
diff --git a/src/net/slipcor/pvparena/commands/AbstractGlobalCommand.java b/src/net/slipcor/pvparena/commands/AbstractGlobalCommand.java
index b3bd5e20b..259359d43 100644
--- a/src/net/slipcor/pvparena/commands/AbstractGlobalCommand.java
+++ b/src/net/slipcor/pvparena/commands/AbstractGlobalCommand.java
@@ -47,6 +47,14 @@ static boolean argCountValid(final CommandSender sender, final String[] args,
 
     public abstract String getName();
 
+    /**
+     * Check if the global command also exists in arena context
+     * @return true if there is the same command for arena context
+     */
+    public boolean hasVersionForArena() {
+        return false;
+    }
+
     @Override
     public boolean hasPerms(final CommandSender sender, final Arena arena) {
         // tabComplete check
diff --git a/src/net/slipcor/pvparena/commands/PAA_Class.java b/src/net/slipcor/pvparena/commands/PAA_Class.java
index ce90b9220..c6769c098 100644
--- a/src/net/slipcor/pvparena/commands/PAA_Class.java
+++ b/src/net/slipcor/pvparena/commands/PAA_Class.java
@@ -8,7 +8,7 @@
 import net.slipcor.pvparena.core.Help.HELP;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
+import net.slipcor.pvparena.managers.InventoryManager;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
@@ -17,6 +17,8 @@
 import java.util.Collections;
 import java.util.List;
 
+import static net.slipcor.pvparena.core.Utils.getSerializableItemStacks;
+
 /**
  * 
  * PVP Arena CLASS Command class
@@ -69,42 +71,20 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
             final Player player = (Player) sender;
             final List items = new ArrayList<>();
 
-            for (final ItemStack is : player.getInventory().getStorageContents()) {
-                if (is != null) {
-                    items.add(is);
-                }
-            }
-
-            final ItemStack[] isItems = new ItemStack[items.size()];
-            int position = 0;
-            for (final ItemStack is : items) {
-                isItems[position++] = is;
-            }
-
-            final String sItems = isItems.length < 1 ? "AIR"
-                    : StringParser.getStringFromItemStacks(isItems);
-            final StringBuilder armor = new StringBuilder("");
-            int pos = 0;
-            for (final ItemStack item : player.getInventory().getArmorContents()) {
-                armor.append(',');
-                armor.append(pos++);
-                armor.append(">>!<<");
-                armor.append(StringParser.getStringFromItemStack(item));
-            }
-            if (player.getInventory().getItemInOffHand() != null) {
-                armor.append(',');
-                armor.append(0);
-                armor.append(">>O<<");
-                armor.append(StringParser.getStringFromItemStack(player.getInventory().getItemInOffHand()));
-            }
-
-            arena.getArenaConfig().setManually("classitems." + args[1], sItems + armor);
+            arena.getArenaConfig().setManually("classitems." + args[1] + ".items", getSerializableItemStacks(player.getInventory().getStorageContents()));
+            arena.getArenaConfig().setManually("classitems." + args[1] + ".offhand", getSerializableItemStacks(player.getInventory().getItemInOffHand()));
+            arena.getArenaConfig().setManually("classitems." + args[1] + ".armor", getSerializableItemStacks(player.getInventory().getArmorContents()));
             arena.getArenaConfig().save();
-            arena.addClass(args[1], StringParser.getItemStacksFromString(sItems), player.getInventory().getItemInOffHand(), player.getInventory().getArmorContents());
+
+            arena.addClass(args[1], player.getInventory().getStorageContents(), player.getInventory().getItemInOffHand(), player.getInventory().getArmorContents());
             Arena.pmsg(player, Language.parse(arena, MSG.CLASS_SAVED, args[1]));
         } else if ("load".equalsIgnoreCase(args[0])) {
             final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(sender.getName());
-            ArenaPlayer.backupAndClearInventory(arena, aPlayer.get());
+            if(aPlayer.getArenaClass() == null) {
+                ArenaPlayer.backupAndClearInventory(arena, aPlayer.get());
+            } else {
+                InventoryManager.clearInventory(aPlayer.get());
+            }
             arena.selectClass(aPlayer, args[1]);
         } else if ("remove".equalsIgnoreCase(args[0])) {
             final Player player = (Player) sender;
diff --git a/src/net/slipcor/pvparena/commands/PAA_ForceWin.java b/src/net/slipcor/pvparena/commands/PAA_ForceWin.java
index f7b9b041e..cb22a6604 100644
--- a/src/net/slipcor/pvparena/commands/PAA_ForceWin.java
+++ b/src/net/slipcor/pvparena/commands/PAA_ForceWin.java
@@ -55,7 +55,8 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
                 for (final ArenaPlayer ap : team.getTeamMembers()) {
                     if (ap.getStatus() == ArenaPlayer.Status.FIGHT) {
                         ap.get().getWorld().strikeLightningEffect(ap.get().getLocation());
-                        final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING, new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf((double) 10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, -0.0D)));
+                        final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING,
+                                10.0);
                         PlayerListener.finallyKillPlayer(arena, ap.get(), e);
                     }
                 }
@@ -74,7 +75,8 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
                     }
                     if (ap.getStatus() == ArenaPlayer.Status.FIGHT) {
                         ap.get().getWorld().strikeLightningEffect(ap.get().getLocation());
-                        final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING, new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf((double) 10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, -0.0D)));
+                        final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING,
+                                10.0);
                         PlayerListener.finallyKillPlayer(arena, ap.get(), e);
                     }
                 }
@@ -87,7 +89,8 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
                     for (final ArenaPlayer ap : team.getTeamMembers()) {
                         if (ap.getStatus() == ArenaPlayer.Status.FIGHT) {
                             ap.get().getWorld().strikeLightningEffect(ap.get().getLocation());
-                            final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING, new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf((double) 10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, -0.0D)));
+                            final EntityDamageEvent e = new EntityDamageEvent(ap.get(), EntityDamageEvent.DamageCause.LIGHTNING,
+                                    10.0);
                             PlayerListener.finallyKillPlayer(arena, ap.get(), e);
                         }
                     }
diff --git a/src/net/slipcor/pvparena/commands/PAA_Install.java b/src/net/slipcor/pvparena/commands/PAA_Install.java
deleted file mode 100644
index 3258ad348..000000000
--- a/src/net/slipcor/pvparena/commands/PAA_Install.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package net.slipcor.pvparena.commands;
-
-import net.slipcor.pvparena.PVPArena;
-import net.slipcor.pvparena.arena.Arena;
-import net.slipcor.pvparena.core.Help;
-import net.slipcor.pvparena.core.Help.HELP;
-import net.slipcor.pvparena.core.Language;
-import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.loadables.ArenaGoal;
-import net.slipcor.pvparena.loadables.ArenaModule;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * 
- * PVP Arena INSTALL Command class
- * 
- *

- * A command to install modules - * - * @author slipcor - * @version v0.10.0 - */ - -public class PAA_Install extends AbstractGlobalCommand { - - public PAA_Install() { - super(new String[]{"pvparena.cmds.install"}); - } - - @Override - public void commit(final CommandSender sender, final String[] args) { - if (!hasPerms(sender)) { - return; - } - - if (!argCountValid(sender, args, new Integer[]{0, 1})) { - return; - } - - // pa install - // pa install ctf - - if (!PVPArena.instance.getConfig().getBoolean("update.modules", true)) { - Arena.pmsg(sender, ChatColor.DARK_RED+Language.parse(MSG.ERROR_MODULE_UPDATE)); - return; - } - - final YamlConfiguration config = new YamlConfiguration(); - try { - config.load(PVPArena.instance.getDataFolder().getPath() - + "/install.yml"); - } catch (final Exception e) { - e.printStackTrace(); - return; - } - - if (args.length == 0) { - listVersions(sender, config, null); - return; - } - - if (config.get(args[0]) != null) { - listVersions(sender, config, args[0]); - return; - } - - Set list = (config == null || config.getConfigurationSection("goals") == null)?new HashSet():config.getConfigurationSection("goals").getKeys(false); - if (list.contains(args[0].toLowerCase())) { - for (final String key : list) { - if (key.equalsIgnoreCase(args[0])) { - if (download("pa_g_" + key + ".jar")) { - PVPArena.instance.getAgm().reload(); - Arena.pmsg(sender, - Language.parse(MSG.INSTALL_DONE, key)); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_INSTALL, key)); - return; - } - } - } else if (list.size() == 0) { - if (download("pa_g_" + args[0].toLowerCase() + ".jar")) { - PVPArena.instance.getAgm().reload(); - Arena.pmsg(sender, - Language.parse(MSG.INSTALL_DONE, args[0].toLowerCase())); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_INSTALL, args[0].toLowerCase())); - } - - list = (config == null || config.getConfigurationSection("mods") == null)?new HashSet():config.getConfigurationSection("mods").getKeys(false); - if (list.contains(args[0].toLowerCase())) { - for (final String key : list) { - if (key.equalsIgnoreCase(args[0])) { - if (download("pa_m_" + key + ".jar")) { - PVPArena.instance.getAmm().reload(); - Arena.pmsg(sender, - Language.parse(MSG.INSTALL_DONE, key)); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_INSTALL, key)); - } - } - } else if (list.size() == 0) { - if (download("pa_m_" + args[0].toLowerCase() + ".jar")) { - PVPArena.instance.getAmm().reload(); - Arena.pmsg(sender, - Language.parse(MSG.INSTALL_DONE, args[0].toLowerCase())); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_INSTALL, args[0].toLowerCase())); - } - } - - private void listVersions(final CommandSender sender, final YamlConfiguration cfg, - final String sub) { - Arena.pmsg(sender, "--- PVP Arena Version Update information ---"); - Arena.pmsg(sender, "[" + ChatColor.COLOR_CHAR + "7uninstalled" + ChatColor.COLOR_CHAR + "r | " + ChatColor.COLOR_CHAR + "einstalled" + ChatColor.COLOR_CHAR + "r]"); - Arena.pmsg(sender, "[" + ChatColor.COLOR_CHAR + "coutdated" + ChatColor.COLOR_CHAR + "r | " + ChatColor.COLOR_CHAR + "alatest version" + ChatColor.COLOR_CHAR + "r]"); - if (sub == null || "goals".equalsIgnoreCase(sub)) { - Arena.pmsg(sender, ChatColor.COLOR_CHAR + "c--- Arena Goals ----> /goals"); - if (cfg.contains("goals")) { - final Set entries = cfg.getConfigurationSection("goals").getKeys( - false); - for (final String key : entries) { - final String latest = cfg.getString("goals." + key); - final ArenaGoal goal = PVPArena.instance.getAgm().getGoalByName(key); - final boolean installed = goal != null; - String version = null; - if (installed) { - version = goal.version(); - } - Arena.pmsg(sender, (installed ? ChatColor.COLOR_CHAR + "e" : ChatColor.COLOR_CHAR + "7") - + key - + ChatColor.COLOR_CHAR + "r - " - + (installed ? latest.equals(version) ? ChatColor.COLOR_CHAR + "a" : ChatColor.COLOR_CHAR + "c" - : "") + version + ChatColor.COLOR_CHAR + "f(" + latest + ')'); - } - } - } - if (sub == null || "mods".equalsIgnoreCase(sub)) { - Arena.pmsg(sender, ChatColor.COLOR_CHAR + "a--- Arena Mods ----> /mods"); - if (cfg.contains("mods")) { - final Set entries = cfg.getConfigurationSection("mods").getKeys( - false); - for (final String key : entries) { - final String latest = cfg.getString("mods." + key); - final ArenaModule mod = PVPArena.instance.getAmm().getModByName(key); - final boolean installed = mod != null; - String version = null; - if (installed) { - version = mod.version(); - } - Arena.pmsg(sender, (installed ? ChatColor.COLOR_CHAR + "e" : ChatColor.COLOR_CHAR + "7") - + key - + ChatColor.COLOR_CHAR + "r - " - + (installed ? latest.equals(version) ? ChatColor.COLOR_CHAR + "a" : ChatColor.COLOR_CHAR + "c" - : "") + version + ChatColor.COLOR_CHAR + "f(" + latest + ')'); - } - } - } - } - private boolean download(final String file) { - return download(file, false); - } - - private boolean download(final String file, final boolean silent) { - - final File source = new File(PVPArena.instance.getDataFolder().getPath() - + "/files/" + file); - - if (!source.exists()) { - if (!silent) { - Arena.pmsg( - Bukkit.getConsoleSender(), - ChatColor.COLOR_CHAR + "cFile '" + ChatColor.COLOR_CHAR + 'r' - + file - + ChatColor.COLOR_CHAR + "c' not found. Please extract the file to /files before trying to install!"); - } - return false; - } - - String folder = null; - if (file.startsWith("pa_g")) { - folder = "/goals/"; - } else if (file.startsWith("pa_m")) { - folder = "/mods/"; - } - if (folder == null) { - PVPArena.instance.getLogger() - .severe("unable to save file: " + file); - return false; - } - try { - final File destination = new File(PVPArena.instance.getDataFolder() - .getPath() + folder + '/' + file); - final FileInputStream stream = new FileInputStream(source); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final byte[] buffer = new byte[8192]; - int bytesRead; - while ((bytesRead = stream.read(buffer)) > 0) { - baos.write(buffer, 0, bytesRead); - } - - final FileOutputStream fos = new FileOutputStream(destination); - fos.write(baos.toByteArray()); - fos.close(); - - PVPArena.instance.getLogger().info("Installed module " + file); - stream.close(); - return true; - } catch (final Exception e) { - e.printStackTrace(); - } - return false; - } - - @Override - public String getName() { - return getClass().getName(); - } - - @Override - public void displayHelp(final CommandSender sender) { - Arena.pmsg(sender, Help.parse(HELP.INSTALL)); - } - - @Override - public List getMain() { - return Collections.singletonList("install"); - } - - @Override - public List getShort() { - return Collections.singletonList("!i"); - } - - @Override - public CommandTree getSubs(final Arena nothing) { - final CommandTree result = new CommandTree<>(null); - result.define(new String[]{"mods"}); - result.define(new String[]{"goals"}); - for (final String string : PVPArena.instance.getAgm().getAllGoalNames()) { - result.define(new String[]{string}); - } - final YamlConfiguration config = new YamlConfiguration(); - try { - config.load(PVPArena.instance.getDataFolder().getPath() - + "/install.yml"); - } catch (final Exception e) { - e.printStackTrace(); - return result; - } - - Set list = config.getConfigurationSection("goals").getKeys(false); - - for (final String key : list) { - result.define(new String[]{key}); - } - - list = config.getConfigurationSection("mods").getKeys(false); - for (final String key : list) { - result.define(new String[]{key}); - } - return result; - } -} diff --git a/src/net/slipcor/pvparena/commands/PAA_Modules.java b/src/net/slipcor/pvparena/commands/PAA_Modules.java new file mode 100644 index 000000000..f2b742a63 --- /dev/null +++ b/src/net/slipcor/pvparena/commands/PAA_Modules.java @@ -0,0 +1,291 @@ +package net.slipcor.pvparena.commands; + +import net.slipcor.pvparena.PVPArena; +import net.slipcor.pvparena.arena.Arena; +import net.slipcor.pvparena.core.Help; +import net.slipcor.pvparena.core.Help.HELP; +import net.slipcor.pvparena.core.Language; +import net.slipcor.pvparena.core.Language.MSG; +import net.slipcor.pvparena.loadables.ArenaModule; +import net.slipcor.pvparena.ncloader.NCBLoadable; +import net.slipcor.pvparena.updater.ModulesUpdater; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.*; + +/** + *

+ * PVP Arena MODULES Command class
+ * 
+ *

+ * A command to manage modules (list, install, uninstall, update, download and upgrade) + * + * @author Eredrim + * @version v1.15 + */ + +public class PAA_Modules extends AbstractGlobalCommand { + + public PAA_Modules() { + super(new String[]{"pvparena.cmds.modules"}); + } + + private static final File FILES_DIR = new File(PVPArena.instance.getDataFolder(),"/files/"); + private static final File MODS_DIR = new File(PVPArena.instance.getDataFolder(),"/mods/"); + + @Override + public void commit(final CommandSender sender, final String[] args) { + if (!this.hasPerms(sender)) { + return; + } + + if (!argCountValid(sender, args, new Integer[]{0, 1, 2})) { + return; + } + + // pa modules + if (args.length == 0) { + listModules(sender); + } else if (args.length == 1) { + switch (args[0]) { + case "list": + listModules(sender); + break; + case "update": + updateModules(sender); + break; + case "download": + ModulesUpdater.downloadModulePack(sender); + break; + case "upgrade": + ModulesUpdater.downloadModulePack(sender); + updateModules(sender); + break; + case "install": + case "uninstall": + Arena.pmsg(sender, Language.parse(MSG.ERROR_INVALID_ARGUMENT_COUNT, "1", "2")); + break; + default: + // Show specific help + } + } else { // 2 args only (if more args, caught above) + if("install".equalsIgnoreCase(args[0])) { + installModule(sender, args[1]); + } else if ("uninstall".equalsIgnoreCase(args[0])) { + uninstallModule(sender, args[1]); + } else { + Arena.pmsg(sender, Language.parse(MSG.ERROR_INVALID_ARGUMENT_COUNT, "2", "1")); + } + } + } + + /** + * List all modules status to sender + * @param sender User who typed the command + */ + private static void listModules(final CommandSender sender) { + Arena.pmsg(sender, "--- PVP Arena Version Update information ---"); + Arena.pmsg(sender, "[" + ChatColor.GRAY + "uninstalled" + ChatColor.RESET + " | " + ChatColor.YELLOW + "installed" + ChatColor.RESET + "]"); + Arena.pmsg(sender, ChatColor.GREEN + "--- Installed Arena Mods ---->"); + + for (final String modName : getModInFilesFolder()) { + final ArenaModule mod = PVPArena.instance.getAmm().getModByName(modName); + Arena.pmsg(sender, (mod != null ? ChatColor.YELLOW : ChatColor.GRAY) + modName + ChatColor.RESET); + } + } + + /** + * Install a module (copying from /files to /mods) + * @param sender User who typed the command + * @param name Module named typed by user + */ + private static void installModule(CommandSender sender, String name) { + Set modList = getModInFilesFolder(); + String modName = name.toLowerCase(); + if (modList.size() != 0 && modList.contains(modName)) { + + if (copyFile("pa_m_" + modName + ".jar")) { + PVPArena.instance.getAmm().reload(); + Arena.pmsg(sender, Language.parse(MSG.INSTALL_DONE, modName)); + } else { + Arena.pmsg(sender, Language.parse(MSG.ERROR_INSTALL, modName)); + } + } else { + Arena.pmsg(sender, Language.parse(MSG.ERROR_UNKNOWN_MODULE, name)); + } + } + + /** + * Uninstall a module + * Unload it and remove it from /mods directory + * @param sender User who typed the command + * @param name Module named typed by user + */ + private static void uninstallModule(CommandSender sender, String name) { + final ArenaModule mod = PVPArena.instance.getAmm().getModByName(name); + if (mod != null) { + String modName = mod.getName(); + String jarName = "pa_m_" + modName.toLowerCase() + ".jar"; + if (remove(jarName)) { + PVPArena.instance.getAmm().reload(); + Arena.pmsg(sender, Language.parse(MSG.UNINSTALL_DONE, modName)); + } else { + Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL, modName)); + FileConfiguration cfg = PVPArena.instance.getConfig(); + List toDelete = cfg.getStringList("todelete"); + toDelete.add(jarName); + cfg.set("todelete", toDelete); + PVPArena.instance.saveConfig(); + Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL2)); + } + } + } + + /** + * Replace all modules of /mods directory by ones of /files directory + * @param sender User who typed the command + */ + private static void updateModules(CommandSender sender) { + final Set modules = new HashSet<>(PVPArena.instance.getAmm().getAllMods()); + + modules.stream() + .filter(mod -> !mod.isInternal()) + .forEach(mod -> { + final File jarFile = new File(FILES_DIR, "pa_m_" + mod.getName().toLowerCase() + ".jar"); + + if (jarFile.exists()) { + uninstallModule(sender, mod.getName()); + installModule(sender, mod.getName()); + } + }); + } + + /** + * List all mods in /files folder + * @return List of mod names + */ + private static Set getModInFilesFolder() { + Set modList = new HashSet<>(); + for (final File file : FILES_DIR.listFiles()) { + final String fileName = file.getName(); + if (fileName.startsWith("pa_m_") && fileName.endsWith(".jar")) { + String modName = fileName.substring(5, fileName.length() - 4); + modList.add(modName); + } + } + return modList; + } + + /** + * Copy a file from /files folder to /mod folder + * @param file file name + * @return true if install was successful + */ + private static boolean copyFile(final String file) { + + final File source = new File(FILES_DIR, file); + + if (!source.exists()) { + Arena.pmsg( + Bukkit.getConsoleSender(), + String.format("%sFile '%s%s%s' not found. Please extract the file to /files before trying to install!", ChatColor.RED, ChatColor.RESET, file, ChatColor.RED)); + return false; + } + + try { + final File destination = new File(MODS_DIR, file); + final FileInputStream stream = new FileInputStream(source); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = stream.read(buffer)) > 0) { + baos.write(buffer, 0, bytesRead); + } + + final FileOutputStream fos = new FileOutputStream(destination); + fos.write(baos.toByteArray()); + fos.close(); + + PVPArena.instance.getLogger().info("Installed module " + file); + stream.close(); + return true; + } catch (final Exception e) { + e.printStackTrace(); + } + return false; + } + + /** + * Remove a mod from /mods folder + * @param file module file name + * @return true if deletion was successful + */ + public static boolean remove(final String file) { + if (!MODS_DIR.exists()) { + PVPArena.instance.getLogger().severe("unable to fetch file: " + file); + return false; + } + + final File destFile = new File(MODS_DIR, file); + + boolean exists = destFile.exists(); + boolean deleted = false; + if (exists) { + deleted = destFile.delete(); + if (!deleted) { + PVPArena.instance.getLogger().severe("could not delete file: " + file); + } + } else { + PVPArena.instance.getLogger().warning("file does not exist: " + file); + } + + return exists && deleted; + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public void displayHelp(final CommandSender sender) { + Arena.pmsg(sender, Help.parse(HELP.INSTALL)); + } + + @Override + public List getMain() { + return Collections.singletonList("modules"); + } + + @Override + public List getShort() { + return Collections.singletonList("!m"); + } + + @Override + public CommandTree getSubs(final Arena nothing) { + final CommandTree result = new CommandTree<>(null); + + result.define(new String[]{"download"}); + result.define(new String[]{"list"}); + result.define(new String[]{"update"}); + result.define(new String[]{"upgrade"}); + + getModInFilesFolder().forEach(modName -> result.define(new String[]{"install", modName})); + + PVPArena.instance.getAmm().getAllMods().stream() + .filter(mod -> !mod.isInternal()) + .map(ArenaModule::getName) + .forEach(modName -> result.define(new String[]{"uninstall", modName})); + + return result; + } +} diff --git a/src/net/slipcor/pvparena/commands/PAA_PlayerClass.java b/src/net/slipcor/pvparena/commands/PAA_PlayerClass.java index c57d1b44e..13439c8f3 100644 --- a/src/net/slipcor/pvparena/commands/PAA_PlayerClass.java +++ b/src/net/slipcor/pvparena/commands/PAA_PlayerClass.java @@ -7,15 +7,14 @@ import net.slipcor.pvparena.core.Help.HELP; import net.slipcor.pvparena.core.Language; import net.slipcor.pvparena.core.Language.MSG; -import net.slipcor.pvparena.core.StringParser; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static net.slipcor.pvparena.core.Utils.getSerializableItemStacks; + /** *

  * PVP Arena PLAYERCLASS Command class
@@ -66,40 +65,13 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
         final Player player = (Player) sender;
 
         if ("save".equalsIgnoreCase(args[0])) {
-            final List items = new ArrayList<>();
-
-            for (final ItemStack is : player.getInventory().getStorageContents()) {
-                if (is != null) {
-                    items.add(is);
-                }
-            }
-
-            final ItemStack[] isItems = new ItemStack[items.size()];
-            int position = 0;
-            for (final ItemStack is : items) {
-                isItems[position++] = is;
-            }
 
-            final String sItems = isItems.length < 1 ? "AIR"
-                    : StringParser.getStringFromItemStacks(isItems);
-            final StringBuilder armor = new StringBuilder("");
-            int pos = 0;
-            for (final ItemStack item : player.getInventory().getArmorContents()) {
-                armor.append(',');
-                armor.append(pos++);
-                armor.append(">>!<<");
-                armor.append(StringParser.getStringFromItemStack(item));
-            }
-            if (player.getInventory().getItemInOffHand() != null) {
-                armor.append(',');
-                armor.append(0);
-                armor.append(">>O<<");
-                armor.append(StringParser.getStringFromItemStack(player.getInventory().getItemInOffHand()));
-            }
-
-            arena.getArenaConfig().setManually("classitems." + className, sItems + armor);
+            arena.getArenaConfig().setManually("classitems." + className + ".items", getSerializableItemStacks(player.getInventory().getStorageContents()));
+            arena.getArenaConfig().setManually("classitems." + className + ".offhand",  getSerializableItemStacks(player.getInventory().getItemInOffHand()));
+            arena.getArenaConfig().setManually("classitems." + className + ".armor", getSerializableItemStacks(player.getInventory().getArmorContents()));
             arena.getArenaConfig().save();
-            arena.addClass(className, isItems, player.getInventory().getItemInOffHand(), player.getInventory().getArmorContents());
+
+            arena.addClass(className, player.getInventory().getStorageContents(), player.getInventory().getItemInOffHand(), player.getInventory().getArmorContents());
             Arena.pmsg(player, Language.parse(arena, MSG.CLASS_SAVED, className));
 
         } else if ("remove".equalsIgnoreCase(args[0])) {
diff --git a/src/net/slipcor/pvparena/commands/PAA_Region.java b/src/net/slipcor/pvparena/commands/PAA_Region.java
index a0812ee69..376f3ebcf 100644
--- a/src/net/slipcor/pvparena/commands/PAA_Region.java
+++ b/src/net/slipcor/pvparena/commands/PAA_Region.java
@@ -64,6 +64,7 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
                 if (sender.getName().equals(selector)) {
                     arena.msg(sender, Language.parse(arena, MSG.ERROR_REGION_YOUSELECTEXIT));
                     selector = null;
+                    activeSelections.remove(sender.getName());
                 } else {
                     arena.msg(sender, Language.parse(arena, MSG.ERROR_REGION_YOUSELECT, arena.getName()));
                     arena.msg(sender, Language.parse(arena, MSG.ERROR_REGION_YOUSELECT2));
@@ -88,12 +89,12 @@ public void commit(final Arena arena, final CommandSender sender, final String[]
             region.getShape().showBorder((Player) sender);
             return;
         }
-        if (args.length == 2 && args[0].equalsIgnoreCase("remove")) {
-            // usage: /pa {arenaname} region remove [regionname] | remove a region
-            final ArenaRegion region = arena.getRegion(args[1]);
+        if (args.length == 2 && args[1].equalsIgnoreCase("remove")) {
+            // usage: /pa {arenaname} region [regionname] remove | remove a region
+            final ArenaRegion region = arena.getRegion(args[0]);
 
             if (region == null) {
-                arena.msg(sender, Language.parse(arena, MSG.ERROR_REGION_NOTFOUND, args[1]));
+                arena.msg(sender, Language.parse(arena, MSG.ERROR_REGION_NOTFOUND, args[0]));
                 return;
             }
             arena.getArenaConfig().setManually("arenaregion." + region.getRegionName(), null);
diff --git a/src/net/slipcor/pvparena/commands/PAA_ReloadAll.java b/src/net/slipcor/pvparena/commands/PAA_ReloadAll.java
new file mode 100644
index 000000000..3e751d230
--- /dev/null
+++ b/src/net/slipcor/pvparena/commands/PAA_ReloadAll.java
@@ -0,0 +1,96 @@
+package net.slipcor.pvparena.commands;
+
+import net.slipcor.pvparena.PVPArena;
+import net.slipcor.pvparena.arena.Arena;
+import net.slipcor.pvparena.core.Help;
+import net.slipcor.pvparena.core.Help.HELP;
+import net.slipcor.pvparena.core.Language;
+import net.slipcor.pvparena.managers.ArenaManager;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 
PVP Arena DEBUG Command class
+ *

+ * A command to toggle debugging + * + * @author slipcor + * @version v0.10.0 + */ + +public class PAA_ReloadAll extends AbstractGlobalCommand { + + public PAA_ReloadAll() { + super(new String[]{"pvparena.cmds.reload"}); + } + + @Override + public void commit(final CommandSender sender, final String[] args) { + if (!hasPerms(sender)) { + return; + } + + if (!argCountValid(sender, args, new Integer[]{0, 1})) { + return; + } + + final PAA_Reload scmd = new PAA_Reload(); + + PVPArena.instance.reloadConfig(); + + final FileConfiguration config = PVPArena.instance.getConfig(); + Language.init(config.getString("language", "en")); + Help.init(config.getString("language", "en")); + + if (args.length > 1 && args[1].equalsIgnoreCase("ymls")) { + Arena.pmsg(sender, Language.parse(Language.MSG.RELOAD_YMLS_DONE)); + return; + } + + final String[] emptyArray = new String[0]; + + for (Arena a : ArenaManager.getArenas()) { + scmd.commit(a, sender, emptyArray); + } + + ArenaManager.load_arenas(); + if (config.getBoolean("use_shortcuts") || config.getBoolean("only_shortcuts")) { + ArenaManager.readShortcuts(config.getConfigurationSection("shortcuts")); + } + } + + @Override + public boolean hasVersionForArena() { + return true; + } + + @Override + public String getName() { + return getClass().getName(); + } + + @Override + public void displayHelp(final CommandSender sender) { + Arena.pmsg(sender, Help.parse(HELP.DEBUG)); + } + + @Override + public List getMain() { + return Collections.singletonList("reload"); + } + + @Override + public List getShort() { + return Collections.singletonList("!rl"); + } + + @Override + public CommandTree getSubs(final Arena nothing) { + final CommandTree result = new CommandTree<>(null); + result.define(new String[]{"ymls"}); + return result; + } +} diff --git a/src/net/slipcor/pvparena/commands/PAA_Set.java b/src/net/slipcor/pvparena/commands/PAA_Set.java index c0d907df4..bf4fdd49d 100644 --- a/src/net/slipcor/pvparena/commands/PAA_Set.java +++ b/src/net/slipcor/pvparena/commands/PAA_Set.java @@ -6,7 +6,6 @@ import net.slipcor.pvparena.core.Help.HELP; import net.slipcor.pvparena.core.Language; import net.slipcor.pvparena.core.Language.MSG; -import net.slipcor.pvparena.core.StringParser; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -18,6 +17,8 @@ import java.util.List; import java.util.Map; +import static net.slipcor.pvparena.core.Utils.getSerializableItemStacks; + /** *

PVP Arena SET Command class
*

@@ -152,22 +153,20 @@ private void set(final CommandSender player, final Arena arena, final String nod Language.parse(arena, MSG.SET_DONE, node, String.valueOf(dValue))); } else if ("tp".equals(type)) { - if (!"exit".equals(value) && !"old".equals(value) - && !"spectator".equals(value)) { + if (!"exit".equals(value) && !"old".equals(value) && !"spectator".equals(value)) { arena.msg(player, Language.parse(arena, MSG.ERROR_ARGUMENT_TYPE, value, "tp (exit|old|spectator|...)")); return; } - arena.getArenaConfig().setManually(node, String.valueOf(value)); + arena.getArenaConfig().setManually(node, value); arena.msg( player, - Language.parse(arena, MSG.SET_DONE, node, - String.valueOf(value))); + Language.parse(arena, MSG.SET_DONE, node, value)); } else if ("material".equals(type)) { if ("hand".equals(value)) { if (player instanceof Player) { - String itemDefinition = StringParser.getStringFromItemStack(((Player) player).getEquipment().getItemInMainHand()); + String itemDefinition = ((Player) player).getEquipment().getItemInMainHand().getType().name(); arena.getArenaConfig().setManually(node, itemDefinition); arena.msg( player, @@ -180,13 +179,10 @@ private void set(final CommandSender player, final Arena arena, final String nod } try { - final Material mat = Material.valueOf(value); + final Material mat = Material.valueOf(value.toUpperCase()); if (mat != Material.AIR) { arena.getArenaConfig().setManually(node, mat.name()); - arena.msg( - player, - Language.parse(arena, MSG.SET_DONE, node, - String.valueOf(mat.name()))); + arena.msg(player, Language.parse(arena, MSG.SET_DONE, node, mat.name())); } arena.getArenaConfig().save(); @@ -200,12 +196,12 @@ private void set(final CommandSender player, final Arena arena, final String nod if ("hand".equals(value)) { if (player instanceof Player) { - String itemDefinition = StringParser.getStringFromItemStack(((Player) player).getEquipment().getItemInMainHand()); - arena.getArenaConfig().setManually(node, itemDefinition); + ItemStack item = ((Player) player).getInventory().getItemInMainHand(); + arena.getArenaConfig().setManually(node, getSerializableItemStacks(item)); arena.msg( player, - Language.parse(arena, MSG.SET_DONE, node, - itemDefinition)); + Language.parse(arena, MSG.SET_DONE, node, item.getType().name())); + arena.getArenaConfig().save(); } else { arena.msg(player, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS)); } @@ -214,36 +210,18 @@ private void set(final CommandSender player, final Arena arena, final String nod if ("inventory".equals(value)) { if (player instanceof Player) { - final String newValue = StringParser.getStringFromItemStacks(((Player) player).getInventory().getContents()); - arena.getArenaConfig().setManually(node, newValue); + final ItemStack[] items = ((Player) player).getInventory().getContents(); + arena.getArenaConfig().setManually(node, getSerializableItemStacks(items)); arena.msg( player, - Language.parse(arena, MSG.SET_DONE, node, - newValue)); + Language.parse(arena, MSG.SET_DONE, node, "inventory")); arena.getArenaConfig().save(); } else { arena.msg(player, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS)); } return; } - - final String[] split = value.split(","); - final ItemStack[] items = new ItemStack[split.length]; - - for (int i = 0; i < split.length; i++) { - items[i] = StringParser.getItemStackFromString(split[i]); - if (items[i] == null) { - arena.msg(player, Language.parse(arena, MSG.ERROR_ARGUMENT_TYPE, String.valueOf(items[i]), - "item")); - return; - } - } - - arena.getArenaConfig().setManually(node, String.valueOf(value)); - arena.msg( - player, - Language.parse(arena, MSG.SET_DONE, node, - String.valueOf(value))); + arena.msg(player, Language.parse(arena, MSG.SET_ITEMS_NOT)); } else { arena.msg( player, diff --git a/src/net/slipcor/pvparena/commands/PAA_Setup.java b/src/net/slipcor/pvparena/commands/PAA_Setup.java index d51c22016..0f1b35d82 100644 --- a/src/net/slipcor/pvparena/commands/PAA_Setup.java +++ b/src/net/slipcor/pvparena/commands/PAA_Setup.java @@ -74,15 +74,15 @@ public void displayHelp(final CommandSender sender) { public static void chat(final Player player, final String message) { final Arena arena = activeSetups.get(player.getName()); - /** - * help | ? - * - * show [region|spawn|block] | display a region/spawn/block with wool blocks", - * region [region] move 2 up | move region [region] 2 blocks up", - * region [region] expand 10 north | expand region [region] 10 block to the north", - * region [region] expand 15 | expand region [region] 15 blocks in all directions", - * all arguments can be abbreviated, e.g. 'r' = 'region', 'e' = 'expand', 'm' = 'move'", - * done | exit setup mode", + /* + help | ? + + show [region|spawn|block] | display a region/spawn/block with wool blocks", + region [region] move 2 up | move region [region] 2 blocks up", + region [region] expand 10 north | expand region [region] 10 block to the north", + region [region] expand 15 | expand region [region] 15 blocks in all directions", + all arguments can be abbreviated, e.g. 'r' = 'region', 'e' = 'expand', 'm' = 'move'", + done | exit setup mode", */ if (message.length() < 1) { return; @@ -107,7 +107,7 @@ class Remover implements Runnable { @Override public void run() { - player.sendBlockChange(location, location.getBlock().getType(), location.getBlock().getData()); + player.sendBlockChange(location, location.getBlock().getType().createBlockData()); } } @@ -122,7 +122,8 @@ public void run() { final Set spawns = SpawnManager.getPASpawnsStartingWith(arena, word[2]); for (final PASpawn spawn : spawns) { final Location loc = spawn.getLocation().toLocation(); - player.sendBlockChange(loc, Material.WOOL, (byte) 0); + + player.sendBlockChange(loc, Material.WHITE_WOOL.createBlockData()); new Remover(loc); } return; @@ -131,17 +132,18 @@ public void run() { final Set blocks = SpawnManager.getPABlocksContaining(arena, word[2]); for (final PABlock block : blocks) { final Location loc = block.getLocation().toLocation(); - player.sendBlockChange(loc, Material.WOOL, (byte) 0); + + player.sendBlockChange(loc, Material.WHITE_WOOL.createBlockData()); new Remover(loc); } return; } } } else if (word[0].startsWith("r")) { - /** - * region [region] move 2 up | move region [region] 2 blocks up", - * region [region] expand 10 north | expand region [region] 10 block to the north", - * region [region] expand 15 out | expand region [region] 15 blocks in all directions", + /* + region [region] move 2 up | move region [region] 2 blocks up", + region [region] expand 10 north | expand region [region] 10 block to the north", + region [region] expand 15 out | expand region [region] 15 blocks in all directions", */ if (word.length == 5) { final ArenaRegion region = arena.getRegion(word[1]); diff --git a/src/net/slipcor/pvparena/commands/PAA_Teams.java b/src/net/slipcor/pvparena/commands/PAA_Teams.java index fd8ece169..627f1043a 100644 --- a/src/net/slipcor/pvparena/commands/PAA_Teams.java +++ b/src/net/slipcor/pvparena/commands/PAA_Teams.java @@ -8,9 +8,9 @@ import net.slipcor.pvparena.core.Language.MSG; import net.slipcor.pvparena.core.StringParser; import org.bukkit.ChatColor; -import org.bukkit.DyeColor; import org.bukkit.command.CommandSender; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -71,10 +71,10 @@ public void commit(final Arena arena, final CommandSender sender, final String[] } else if ("add".equals(args[0])) { try { - final DyeColor dColor = DyeColor.valueOf(args[2].toUpperCase()); - final ArenaTeam newTeam = new ArenaTeam(args[1], dColor.name()); + final ChatColor color = ChatColor.valueOf(args[2].toUpperCase()); + final ArenaTeam newTeam = new ArenaTeam(args[1], color.name()); arena.getTeams().add(newTeam); - arena.getArenaConfig().setManually("teams." + newTeam.getName(), dColor.name()); + arena.getArenaConfig().setManually("teams." + newTeam.getName(), color.name()); arena.getArenaConfig().save(); arena.msg(sender, Language.parse(arena, MSG.TEAMS_ADD, newTeam.getColoredName())); @@ -128,7 +128,9 @@ public CommandTree getSubs(final Arena arena) { } for (final String team : arena.getTeamNames()) { result.define(new String[]{"remove", team}); - result.define(new String[]{"set", team}); + Arrays.stream(ChatColor.values()).forEach(color -> + result.define(new String[]{"set", team, color.name()}) + ); } return result; } diff --git a/src/net/slipcor/pvparena/commands/PAA_Uninstall.java b/src/net/slipcor/pvparena/commands/PAA_Uninstall.java deleted file mode 100644 index d437cc362..000000000 --- a/src/net/slipcor/pvparena/commands/PAA_Uninstall.java +++ /dev/null @@ -1,219 +0,0 @@ -package net.slipcor.pvparena.commands; - -import net.slipcor.pvparena.PVPArena; -import net.slipcor.pvparena.arena.Arena; -import net.slipcor.pvparena.core.Help; -import net.slipcor.pvparena.core.Help.HELP; -import net.slipcor.pvparena.core.Language; -import net.slipcor.pvparena.core.Language.MSG; -import net.slipcor.pvparena.loadables.ArenaGoal; -import net.slipcor.pvparena.loadables.ArenaModule; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - *

PVP Arena UNINSTALL Command class
- *

- * A command to uninstall modules - * - * @author slipcor - * @version v0.10.0 - */ - -public class PAA_Uninstall extends AbstractGlobalCommand { - - public PAA_Uninstall() { - super(new String[]{"pvparena.cmds.uninstall"}); - } - - @Override - public void commit(final CommandSender sender, final String[] args) { - if (!hasPerms(sender)) { - return; - } - - if (!argCountValid(sender, args, - new Integer[]{0, 1})) { - return; - } - - if (!PVPArena.instance.getConfig().getBoolean("update.modules", true)) { - Arena.pmsg(sender, ChatColor.DARK_RED+Language.parse(MSG.ERROR_MODULE_UPDATE)); - return; - } - - // pa install - // pa install ctf - - final YamlConfiguration config = new YamlConfiguration(); - try { - config.load(PVPArena.instance.getDataFolder().getPath() + "/install.yml"); - } catch (final Exception e) { - } - - if (args.length == 0) { - listVersions(sender, config, null); - return; - } - - if (config.get(args[0]) != null) { - listVersions(sender, config, args[1]); - return; - } - - final String name = args[0].toLowerCase(); - final ArenaGoal goal = PVPArena.instance.getAgm().getGoalByName(name); - if (goal != null) { - if (remove("pa_g_" + goal.getName().toLowerCase() + ".jar")) { - PVPArena.instance.getAgm().reload(); - Arena.pmsg(sender, Language.parse(MSG.UNINSTALL_DONE, goal.getName())); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL, goal.getName())); - FileConfiguration cfg = PVPArena.instance.getConfig(); - List toDelete = cfg.getStringList("todelete"); - if (toDelete == null){ - toDelete = new ArrayList<>(); - } - toDelete.add("pa_g_" + goal.getName().toLowerCase() + ".jar"); - cfg.set("todelete", toDelete); - PVPArena.instance.saveConfig(); - Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL2)); - return; - } - final ArenaModule mod = PVPArena.instance.getAmm().getModByName(name); - if (mod != null) { - if (remove("pa_m_" + mod.getName().toLowerCase() + ".jar")) { - PVPArena.instance.getAmm().reload(); - Arena.pmsg(sender, Language.parse(MSG.UNINSTALL_DONE, mod.getName())); - return; - } - Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL, mod.getName())); - FileConfiguration cfg = PVPArena.instance.getConfig(); - List toDelete = cfg.getStringList("todelete"); - if (toDelete == null){ - toDelete = new ArrayList<>(); - } - toDelete.add("pa_m_" + mod.getName().toLowerCase() + ".jar"); - cfg.set("todelete", toDelete); - PVPArena.instance.saveConfig(); - Arena.pmsg(sender, Language.parse(MSG.ERROR_UNINSTALL2)); - } - } - - private void listVersions(final CommandSender sender, final YamlConfiguration cfg, - final String sub) { - Arena.pmsg(sender, "--- PVP Arena Version Update information ---"); - Arena.pmsg(sender, "[" + ChatColor.COLOR_CHAR + "7uninstalled" + ChatColor.COLOR_CHAR + "r | " + ChatColor.COLOR_CHAR + "einstalled" + ChatColor.COLOR_CHAR + "r]"); - Arena.pmsg(sender, "[" + ChatColor.COLOR_CHAR + "coutdated" + ChatColor.COLOR_CHAR + "r | " + ChatColor.COLOR_CHAR + "alatest version" + ChatColor.COLOR_CHAR + "r]"); - if (sub == null || "arenas".equalsIgnoreCase(sub)) { - Arena.pmsg(sender, ChatColor.COLOR_CHAR + "c--- Arena Goals ----> /goals"); - final Set entries = cfg.getConfigurationSection("goals").getKeys( - false); - for (final String key : entries) { - final String value = cfg.getString("goals." + key); - final ArenaGoal goal = PVPArena.instance.getAgm().getGoalByName(key); - final boolean installed = goal != null; - String version = null; - if (installed) { - version = goal.version(); - } - Arena.pmsg(sender, (installed ? ChatColor.COLOR_CHAR + "e" : ChatColor.COLOR_CHAR + "7") - + key - + ChatColor.COLOR_CHAR + "r - " - + (installed ? value.equals(version) ? ChatColor.COLOR_CHAR + "a" : ChatColor.COLOR_CHAR + "c" - : "") + value); - } - } - if (sub == null || "mods".equalsIgnoreCase(sub)) { - Arena.pmsg(sender, ChatColor.COLOR_CHAR + "a--- Arena Mods ----> /mods"); - final Set entries = cfg.getConfigurationSection("mods").getKeys( - false); - for (final String key : entries) { - final String value = cfg.getString("mods." + key); - final ArenaModule mod = PVPArena.instance.getAmm().getModByName(key); - final boolean installed = mod != null; - String version = null; - if (installed) { - version = mod.version(); - } - Arena.pmsg(sender, (installed ? ChatColor.COLOR_CHAR + "e" : ChatColor.COLOR_CHAR + "7") - + key - + ChatColor.COLOR_CHAR + "r - " - + (installed ? value.equals(version) ? ChatColor.COLOR_CHAR + "a" : ChatColor.COLOR_CHAR + "c" - : "") + value); - } - - } - } - - @Override - public String getName() { - return getClass().getName(); - } - - public static boolean remove(final String file) { - String folder = null; - if (file.startsWith("pa_g")) { - folder = "/goals/"; - } else if (file.startsWith("pa_m")) { - folder = "/mods/"; - } - if (folder == null) { - PVPArena.instance.getLogger().severe("unable to fetch file: " + file); - return false; - } - final File destination = new File(PVPArena.instance.getDataFolder().getPath() - + folder); - - final File destFile = new File(destination, file); - - boolean exists = destFile.exists(); - boolean deleted = false; - if (exists) { - deleted = destFile.delete(); - if (!deleted) { - PVPArena.instance.getLogger().severe("could not delete file: " + file); - } - } else { - PVPArena.instance.getLogger().warning("file does not exist: " + file); - } - - return exists && deleted; - } - - @Override - public void displayHelp(final CommandSender sender) { - Arena.pmsg(sender, Help.parse(HELP.UNINSTALL)); - } - - @Override - public List getMain() { - return Collections.singletonList("uninstall"); - } - - @Override - public List getShort() { - return Collections.singletonList("!ui"); - } - - @Override - public CommandTree getSubs(final Arena nothing) { - final CommandTree result = new CommandTree<>(null); - for (final String string : PVPArena.instance.getAgm().getAllGoalNames()) { - result.define(new String[]{string}); - } - for (final ArenaModule mod : PVPArena.instance.getAmm().getAllMods()) { - result.define(new String[]{mod.getName()}); - } - return result; - } -} diff --git a/src/net/slipcor/pvparena/commands/PAA_Update.java b/src/net/slipcor/pvparena/commands/PAA_Update.java deleted file mode 100644 index 89aecadf1..000000000 --- a/src/net/slipcor/pvparena/commands/PAA_Update.java +++ /dev/null @@ -1,123 +0,0 @@ -package net.slipcor.pvparena.commands; - -import net.slipcor.pvparena.PVPArena; -import net.slipcor.pvparena.arena.Arena; -import net.slipcor.pvparena.core.Help; -import net.slipcor.pvparena.core.Help.HELP; -import net.slipcor.pvparena.core.Language; -import net.slipcor.pvparena.loadables.ArenaModule; -import net.slipcor.pvparena.ncloader.NCBLoadable; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -import java.io.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - *

PVP Arena UPDATE Command class
- *

- * A command to update modules - * - * @author slipcor - * @version v0.10.0 - */ - -public class PAA_Update extends AbstractGlobalCommand { - - public PAA_Update() { - super(new String[]{"pvparena.cmds.update"}); - } - - @Override - public void commit(final CommandSender sender, final String[] args) { - if (!PVPArena.instance.getConfig().getBoolean("update.modules", true)) { - Arena.pmsg(sender, ChatColor.DARK_RED+ Language.parse(Language.MSG.ERROR_MODULE_UPDATE)); - return; - } - if (!hasPerms(sender)) { - return; - } - - final Set modules = new HashSet<>(); - - if (args.length < 1 || "mods".equals(args[0])) { - modules.addAll(PVPArena.instance.getAmm().getAllMods()); - } else if (args.length < 1 || "goals".equals(args[0])) { - modules.addAll(PVPArena.instance.getAgm().getAllGoals()); - } else if (args.length < 1 || "regionshapes".equals(args[0])) { - modules.addAll(PVPArena.instance.getArsm().getRegions()); - } - - if (!modules.isEmpty()) { - for (final NCBLoadable mod : modules) { - if (mod.isInternal()) { - continue; - } - - final File destination = new File(PVPArena.instance.getDataFolder().getPath() - + "/files/"); - final File destFileG = new File(destination, "pa_g_" + mod.getName().toLowerCase() + ".jar"); - final File destFileM = new File(destination, "pa_m_" + mod.getName().toLowerCase() + ".jar"); - - if (!destFileG.exists() && !destFileM.exists()) { - continue; - } - - final PAA_Uninstall uninstall = new PAA_Uninstall(); - if (!uninstall.hasPerms(sender)) { - return; - } - uninstall.commit(sender, new String[]{mod.getName()}); - final PAA_Install install = new PAA_Install(); - if (!install.hasPerms(sender)) { - return; - } - install.commit(sender, new String[]{mod.getName()}); - } - return; - } - - final PAA_Uninstall uninstall = new PAA_Uninstall(); - uninstall.commit(sender, args); - final PAA_Install install = new PAA_Install(); - install.commit(sender, args); - } - - - @Override - public String getName() { - return getClass().getName(); - } - - @Override - public void displayHelp(final CommandSender sender) { - Arena.pmsg(sender, Help.parse(HELP.UPDATE)); - } - - @Override - public List getMain() { - return Collections.singletonList("update"); - } - - @Override - public List getShort() { - return Collections.singletonList("!u"); - } - - @Override - public CommandTree getSubs(final Arena nothing) { - final CommandTree result = new CommandTree<>(null); - result.define(new String[]{"mods"}); - result.define(new String[]{"goals"}); - for (final String string : PVPArena.instance.getAgm().getAllGoalNames()) { - result.define(new String[]{string}); - } - for (final ArenaModule mod : PVPArena.instance.getAmm().getAllMods()) { - result.define(new String[]{mod.getName()}); - } - return result; - } -} diff --git a/src/net/slipcor/pvparena/commands/PAG_Arenaclass.java b/src/net/slipcor/pvparena/commands/PAG_Arenaclass.java index 6b5a0e5d9..429ff74db 100644 --- a/src/net/slipcor/pvparena/commands/PAG_Arenaclass.java +++ b/src/net/slipcor/pvparena/commands/PAG_Arenaclass.java @@ -22,6 +22,10 @@ import java.util.Set; import java.util.TreeSet; +import static java.util.Arrays.asList; +import static net.slipcor.pvparena.arena.ArenaPlayer.Status.FIGHT; +import static net.slipcor.pvparena.arena.ArenaPlayer.Status.LOUNGE; + /** *

PVP Arena JOIN Command class
*

@@ -38,7 +42,7 @@ public PAG_Arenaclass() { @Override public void commit(final Arena arena, final CommandSender sender, final String[] args) { - if (!hasPerms(sender, arena) || !arena.getArenaConfig().getBoolean(CFG.USES_INGAMECLASSSWITCH)) { + if (!hasPerms(sender, arena)) { return; } @@ -46,10 +50,25 @@ public void commit(final Arena arena, final CommandSender sender, final String[] return; } - if (args.length < 1) { + if (!(sender instanceof Player)) { + Arena.pmsg(sender, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS)); + return; + } + + final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(sender.getName()); + + ArenaPlayer.Status pStatus = aPlayer.getStatus(); + + // Player can change arena class only in lounge or in fight with ingameClassSwith parameter set to true + if(!arena.equals(aPlayer.getArena()) || !asList(LOUNGE, FIGHT).contains(pStatus) || + (pStatus == FIGHT && !arena.getArenaConfig().getBoolean(CFG.USES_INGAMECLASSSWITCH))) { + return; + } + + if (args.length < 1 || "custom".equalsIgnoreCase(args[0])) { Set classes = new TreeSet<>(); for (ArenaClass ac : arena.getClasses()) { - if (ac.getName().equals("custom")) { + if ("custom".equalsIgnoreCase(ac.getName())) { continue; } classes.add(ChatColor.GREEN + ac.getName() + ChatColor.WHITE); @@ -58,13 +77,6 @@ public void commit(final Arena arena, final CommandSender sender, final String[] return; } - if (!(sender instanceof Player)) { - Arena.pmsg(sender, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS)); - return; - } - - final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(sender.getName()); - final ArenaClass aClass = arena.getClass(args[0]); if (aClass == null) { @@ -151,12 +163,13 @@ public List getShort() { @Override public CommandTree getSubs(final Arena arena) { final CommandTree result = new CommandTree<>(null); - if (arena == null) { - return result; - } - for (final ArenaClass aClass : arena.getClasses()) { - result.define(new String[]{aClass.getName()}); + + if (arena != null) { + arena.getClasses().stream() + .filter(aClass -> !"custom".equalsIgnoreCase(aClass.getName())) + .forEach(aClass -> result.define(new String[]{aClass.getName()})); } + return result; } } diff --git a/src/net/slipcor/pvparena/commands/PAG_Join.java b/src/net/slipcor/pvparena/commands/PAG_Join.java index 8b495367b..94f1c61dc 100644 --- a/src/net/slipcor/pvparena/commands/PAG_Join.java +++ b/src/net/slipcor/pvparena/commands/PAG_Join.java @@ -86,9 +86,7 @@ public void commit(final Arena arena, final CommandSender sender, final String[] arena.getDebugger().i("Join_2", sender); arena.msg(sender, Language.parse(arena, MSG.ERROR_ARENA_ALREADY_PART_OF, ArenaManager.getIndirectArenaName(arena))); } else { - if (PACheck.handleJoin(arena, sender, args)) { - arena.setupScoreboard(aPlayer.get()); - } + PACheck.handleJoin(arena, sender, args); } } else { final Arena pArena = aPlayer.getArena(); diff --git a/src/net/slipcor/pvparena/commands/PAG_Leave.java b/src/net/slipcor/pvparena/commands/PAG_Leave.java index da8e053b5..501eb4ff7 100644 --- a/src/net/slipcor/pvparena/commands/PAG_Leave.java +++ b/src/net/slipcor/pvparena/commands/PAG_Leave.java @@ -7,6 +7,7 @@ import net.slipcor.pvparena.core.Help.HELP; import net.slipcor.pvparena.core.Language; import net.slipcor.pvparena.core.Language.MSG; +import net.slipcor.pvparena.loadables.ArenaModule; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -45,9 +46,19 @@ public void commit(final Arena arena, final CommandSender sender, final String[] final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(sender.getName()); - if (!arena.hasPlayer(aPlayer.get())) { + // Handle modules which need to leave even if players aren't in an arena + for (final ArenaModule mod : arena.getMods()) { + if(mod.handleSpecialLeave(aPlayer)) { + return; + } + } - arena.msg(sender, Language.parse(arena, MSG.ERROR_NOT_IN_ARENA)); + if (!arena.hasPlayer(aPlayer.get())) { + if(PAA_Edit.activeEdits.containsKey(sender.getName())) { + new PAA_Edit().commit(arena, sender, args); + } else { + arena.msg(sender, Language.parse(arena, MSG.ERROR_NOT_IN_ARENA)); + } return; } arena.callLeaveEvent(aPlayer.get()); diff --git a/src/net/slipcor/pvparena/commands/PAG_Spectate.java b/src/net/slipcor/pvparena/commands/PAG_Spectate.java index 40082880a..a46415d67 100644 --- a/src/net/slipcor/pvparena/commands/PAG_Spectate.java +++ b/src/net/slipcor/pvparena/commands/PAG_Spectate.java @@ -49,9 +49,7 @@ public void commit(final Arena arena, final CommandSender sender, final String[] return; } - if (PACheck.handleSpectate(arena, sender)) { - arena.setupScoreboard((Player) sender); - } + PACheck.handleSpectate(arena, sender); } @Override diff --git a/src/net/slipcor/pvparena/commands/PAI_ArenaList.java b/src/net/slipcor/pvparena/commands/PAI_ArenaList.java index 2655405ac..fcdd5b628 100644 --- a/src/net/slipcor/pvparena/commands/PAI_ArenaList.java +++ b/src/net/slipcor/pvparena/commands/PAI_ArenaList.java @@ -52,6 +52,11 @@ public void commit(final CommandSender sender, final String[] args) { Arena.pmsg(sender, Language.parse(MSG.ARENA_LIST, StringParser.joinList(names, ", "))); } + @Override + public boolean hasVersionForArena() { + return true; + } + @Override public String getName() { return getClass().getName(); diff --git a/src/net/slipcor/pvparena/commands/PAI_GlobalStats.java b/src/net/slipcor/pvparena/commands/PAI_GlobalStats.java new file mode 100644 index 000000000..f42826180 --- /dev/null +++ b/src/net/slipcor/pvparena/commands/PAI_GlobalStats.java @@ -0,0 +1,73 @@ +package net.slipcor.pvparena.commands; + +import net.slipcor.pvparena.arena.Arena; +import net.slipcor.pvparena.core.Help; +import net.slipcor.pvparena.core.Help.HELP; +import net.slipcor.pvparena.managers.StatisticsManager.Type; +import org.bukkit.command.CommandSender; + +import java.util.Collections; +import java.util.List; + +/** + *

PVP Arena STATS Command class
+ *

+ * A command to display the player statistics + * + * @author slipcor + * @version v0.10.0 + */ + +public class PAI_GlobalStats extends AbstractGlobalCommand { + + public PAI_GlobalStats() { + super(new String[]{"pvparena.user", "pvparena.cmds.stats"}); + } + + @Override + public void commit(final CommandSender sender, final String[] args) { + if (!hasPerms(sender)) { + return; + } + + if (!argCountValid(sender, args, new Integer[]{1})) { + return; + } + + new PAI_Stats().commit(null, sender, args); + } + + @Override + public boolean hasVersionForArena() { + return true; + } + + @Override + public String getName() { + return getClass().getName(); + } + + @Override + public void displayHelp(final CommandSender sender) { + Arena.pmsg(sender, Help.parse(HELP.STATS)); + } + + @Override + public List getMain() { + return Collections.singletonList("stats"); + } + + @Override + public List getShort() { + return Collections.singletonList("-s"); + } + + @Override + public CommandTree getSubs(final Arena arena) { + final CommandTree result = new CommandTree<>(null); + for (final Type val : Type.values()) { + result.define(new String[]{val.name()}); + } + return result; + } +} diff --git a/src/net/slipcor/pvparena/commands/PAI_Info.java b/src/net/slipcor/pvparena/commands/PAI_Info.java index 4ea4e2fae..42ce9da7b 100644 --- a/src/net/slipcor/pvparena/commands/PAI_Info.java +++ b/src/net/slipcor/pvparena/commands/PAI_Info.java @@ -123,7 +123,7 @@ public void commit(final Arena arena, final CommandSender sender, final String[] arena.msg(sender, "minplayers: " + arena.getArenaConfig().getInt(CFG.ITEMS_MINPLAYERS) + " | " + "rewards: " + - arena.getArenaConfig().getString(CFG.ITEMS_REWARDS) + " | " + + StringParser.getItems(arena.getArenaConfig().getItems(CFG.ITEMS_REWARDS)) + " | " + StringParser.colorVar("random", arena.getArenaConfig().getBoolean(CFG.ITEMS_RANDOM))); diff --git a/src/net/slipcor/pvparena/commands/PAI_Stats.java b/src/net/slipcor/pvparena/commands/PAI_Stats.java index f2e1eab77..862e25942 100644 --- a/src/net/slipcor/pvparena/commands/PAI_Stats.java +++ b/src/net/slipcor/pvparena/commands/PAI_Stats.java @@ -7,11 +7,13 @@ import net.slipcor.pvparena.core.Language.MSG; import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.managers.StatisticsManager; -import net.slipcor.pvparena.managers.StatisticsManager.type; +import net.slipcor.pvparena.managers.StatisticsManager.Type; import org.bukkit.command.CommandSender; import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; /** *

PVP Arena STATS Command class
@@ -38,23 +40,21 @@ public void commit(final Arena arena, final CommandSender sender, final String[] return; } - final type statType = type.getByString(args[0]); + final Type statType = Type.getByString(args[0]); if (statType == null) { - Arena.pmsg(sender, Language.parse(arena, MSG.STATS_TYPENOTFOUND, StringParser.joinArray(type.values(), ", ").replace("NULL, ", ""))); + Arena.pmsg(sender, Language.parse(arena, MSG.STATS_TYPENOTFOUND, StringParser.joinArray(Type.values(), ", ").replace("NULL, ", ""))); return; } - final String[] values = StatisticsManager.read(StatisticsManager.getStats(arena, statType), statType, arena == null); - final String[] names = StatisticsManager.read(StatisticsManager.getStats(arena, statType), type.NULL, arena == null); + Map playersStats = StatisticsManager.getStats(arena, statType); int max = 10; if (args.length > 1) { try { max = Integer.parseInt(args[1]); - } catch (final Exception e) { - max = 10; + } catch (NumberFormatException ignored) { } } @@ -65,9 +65,10 @@ public void commit(final Arena arena, final CommandSender sender, final String[] Arena.pmsg(sender, s1); - for (int i = 0; i < max && i < names.length && i < values.length; i++) { - Arena.pmsg(sender, names[i] + ": " + values[i]); - } + playersStats.entrySet().stream() + .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) + .limit(max) + .forEach(stat -> Arena.pmsg(sender, stat.getKey() + " : " + stat.getValue())); } @Override @@ -93,7 +94,7 @@ public List getShort() { @Override public CommandTree getSubs(final Arena arena) { final CommandTree result = new CommandTree<>(null); - for (final type val : type.values()) { + for (final Type val : Type.values()) { result.define(new String[]{val.name()}); } return result; diff --git a/src/net/slipcor/pvparena/core/ColorUtils.java b/src/net/slipcor/pvparena/core/ColorUtils.java new file mode 100644 index 000000000..abe8b17c1 --- /dev/null +++ b/src/net/slipcor/pvparena/core/ColorUtils.java @@ -0,0 +1,148 @@ +package net.slipcor.pvparena.core; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Rotatable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class ColorUtils { + + private static final Debug DEBUG = new Debug(18); + + private ColorUtils() { + } + + public static Material getWoolMaterialFromDyeColor(final String color) { + return getColoredMaterial(DyeColor.valueOf(color), Material.WHITE_WOOL); + } + + public static Material getWoolMaterialFromChatColor(final ChatColor color) { + return getColoredMaterialFromChatColor(color, Material.WHITE_WOOL); + } + + /** + * Get a colored Material from a chat color and any colorable material + * @param color Color from chat + * @param material Colorable material like Wool, Concrete or Stained glass + * @return + */ + public static Material getColoredMaterialFromChatColor(final ChatColor color, final Material material) { + /* + Unsupported: + ChatColor.AQUA + Material.BROWN_WOOL + */ + + DyeColor dyeColor = getDyeColorFromChatColor(color); + return getColoredMaterial(dyeColor, material); + } + + public static DyeColor getDyeColorFromChatColor(ChatColor color) { + try { + return DyeColor.valueOf(parseDyeColorToChatColor(color.name(), false)); + } catch (IllegalArgumentException e) { + DEBUG.i("ChatColor " + color.name() + " can't be cast to DyeColor => set BROWN"); + return DyeColor.BROWN; + } + } + + public static ChatColor getChatColorFromDyeColor(final String color) { + return ChatColor.valueOf(parseDyeColorToChatColor(color, true)); + } + + private static String parseDyeColorToChatColor(final String color, final boolean forward) { + /* + following colors are the sames (ignore): WHITE, YELLOW, BLACK + colors not being able to parse: chat-AQUA, wool-brown + */ + + final List wool = Arrays.asList("ORANGE", "MAGENTA", "LIGHT_BLUE", "LIME", "PINK", "GRAY", "LIGHT_GRAY", + "PURPLE", "BLUE", "GREEN", "RED", "CYAN"); + final List chat = Arrays.asList("GOLD", "LIGHT_PURPLE", "BLUE", "GREEN", "RED", "DARK_GRAY", "GRAY", + "DARK_PURPLE", "DARK_BLUE", "DARK_GREEN", "DARK_RED", "DARK_AQUA"); + + if (forward) { + if (wool.contains(color)) { + return chat.get(wool.indexOf(color)); + } + } else { + if (chat.contains(color)) { + return wool.get(chat.indexOf(color)); + } + } + return color; + } + + /** + * Check if a material can be colored + * @param type Material to check + * @return true if material can be colored + */ + public static boolean isColorableMaterial(Material type) { + return getColorableSuffixes().contains(getMaterialSuffix(type)); + } + + /** + * Get a colored material applying dye color on a material + * @param dyeColor DyeColor to get color + * @param typeMaterial Material used to get type + * @return colored material + */ + public static Material getColoredMaterial(DyeColor dyeColor, Material typeMaterial) { + String color = dyeColor.name(); + String materialSuffix = getMaterialSuffix(typeMaterial); + return Material.valueOf(color + "_" + materialSuffix); + } + + public static boolean isSubType(Material type, Material check) { + return (type == check) || (isColorableMaterial(type) && getMaterialSuffix(type).equals(getMaterialSuffix(check))); + } + + private static String getMaterialSuffix(Material material) { + return getColorableSuffixes().stream() + .filter(suffix -> material.name().endsWith(suffix)) + .findFirst() + .orElse(""); + } + + /** + * Get the list of all colorable blocks + */ + private static List getColorableSuffixes() { + return Stream.of(Material.values()) + .filter(m -> m.name().startsWith("MAGENTA_")) + .filter(Material::isBlock) + .map(m -> m.name().split("MAGENTA_", 2)[1]) + .collect(Collectors.toList()); + } + + /** + * Change flag color keeping rotation and facing + * @param flagBlock Block (location) of the flag + * @param flagColor New flag color + */ + public static void setNewFlagColor(Block flagBlock, ChatColor flagColor) { + final BlockData originalBlockData = flagBlock.getBlockData().clone(); + Material newMaterial = ColorUtils.getColoredMaterialFromChatColor(flagColor, flagBlock.getType()); + BlockData newData = Bukkit.getServer().createBlockData(newMaterial); + + if(originalBlockData instanceof Directional) { + ((Directional) newData).setFacing(((Directional) originalBlockData).getFacing()); + } + + if(originalBlockData instanceof Rotatable) { + ((Rotatable) newData).setRotation(((Rotatable) originalBlockData).getRotation()); + } + + flagBlock.setBlockData(newData); + } +} diff --git a/src/net/slipcor/pvparena/core/Config.java b/src/net/slipcor/pvparena/core/Config.java index 051e3f4f8..a6af40978 100644 --- a/src/net/slipcor/pvparena/core/Config.java +++ b/src/net/slipcor/pvparena/core/Config.java @@ -20,6 +20,9 @@ import java.io.File; import java.util.*; +import static net.slipcor.pvparena.core.ItemStackUtils.getItemStacksFromConfig; +import static net.slipcor.pvparena.core.Utils.getSerializableItemStacks; + /** *
  * Configuration class
@@ -74,16 +77,17 @@ public enum CFG {
         GENERAL_SMARTSPAWN("general.smartspawn", false, null),
         GENERAL_TIME("general.time", -1, null),
         GENERAL_TYPE("general.type", "none", null),
-        GENERAL_WAND("general.wand", Material.STICK.name(), false, null),
+        GENERAL_WAND("general.wand", Material.STICK, null),
 
         GOAL_ADDLIVESPERPLAYER("goal.livesPerPlayer", false, null),
 
-        ITEMS_EXCLUDEFROMDROPS("items.excludeFromDrops", "none", true, null),
-        ITEMS_KEEPONRESPAWN("items.keepOnRespawn", "none", true, null),
+        ITEMS_EXCLUDEFROMDROPS("items.excludeFromDrops", new ItemStack[0], null),
+        ITEMS_KEEPONRESPAWN("items.keepOnRespawn", new ItemStack[0], null),
+        ITEMS_KEEPALLONRESPAWN("items.keepAllOnRespawn", false, null),
         ITEMS_MINPLAYERS("items.minplayers", 2, null),
         ITEMS_RANDOM("items.random", true, null),
-        ITEMS_REWARDS("items.rewards", "none", true, null),
-        ITEMS_TAKEOUTOFGAME("items.takeOutOfGame", "none", true, null),
+        ITEMS_REWARDS("items.rewards", new ItemStack[0], null),
+        ITEMS_TAKEOUTOFGAME("items.takeOutOfGame", new ItemStack[0], null),
 
         JOIN_RANGE("join.range", 0, null),
         JOIN_FORCE("join.forceregionjoin", false, null),
@@ -124,7 +128,7 @@ public enum CFG {
         PLAYER_HEALTH("player.health", -1, null),
         PLAYER_HEALFORKILL("player.healforkill", false, null),
         PLAYER_HUNGER("player.hunger", true, null),
-        PLAYER_ITEMSONKILL("player.itemsonkill", "none", true, null),
+        PLAYER_ITEMSONKILL("player.itemsonkill", new ItemStack[0], null),
         PLAYER_MAYCHANGEARMOR("player.mayChangeArmor", true, null),
         PLAYER_MAXHEALTH("player.maxhealth", -1, null),
         PLAYER_PREVENTDEATH("player.preventDeath", true, null),
@@ -140,7 +144,7 @@ public enum CFG {
         PROTECT_SPAWN("protection.spawn", 0, null),
 
         READY_AUTOCLASS("ready.autoClass", "none", null),
-        READY_BLOCK("ready.block", Material.IRON_BLOCK.name(), false, null),
+        READY_BLOCK("ready.block", Material.IRON_BLOCK, null),
         READY_CHECKEACHPLAYER("ready.checkEachPlayer", false, null),
         READY_CHECKEACHTEAM("ready.checkEachTeam", true, null),
         READY_ENFORCECOUNTDOWN("ready.enforceCountdown", false, null),
@@ -180,17 +184,7 @@ public enum CFG {
         USES_WOOLHEAD("uses.woolHead", false, null),
 
         // ----------
-
-        GOAL_BEACONS_ANNOUNCEOFFSET("goal.beacons.spamoffset", 3, "Beacons"),
-        GOAL_BEACONS_BOSSBAR("goal.beacons.beacBossBar", true, "Beacons"),
-        GOAL_BEACONS_CHANGESECONDS("goal.beacons.changeseconds", 30, "Beacons"),
-        GOAL_BEACONS_CHANGEONCLAIM("goal.beacons.changeonclaim", false, "Beacons"),
-        GOAL_BEACONS_CLAIMRANGE("goal.beacons.claimrange", 3, "Beacons"),
-        GOAL_BEACONS_LIVES("goal.beacons.blives", 10, "Beacons"),
-        GOAL_BEACONS_TICKINTERVAL("goal.beacons.tickinterval", 60, "Beacons"),
-        GOAL_BEACONS_TICKREWARD("goal.beacons.tickreward", 1, "Beacons"),
-
-        GOAL_BLOCKDESTROY_BLOCKTYPE("goal.blockdestroy.blocktype", "IRON_BLOCK", false, "BlockDestroy"),
+        GOAL_BLOCKDESTROY_BLOCKTYPE("goal.blockdestroy.blocktype", Material.IRON_BLOCK, "BlockDestroy"),
         GOAL_BLOCKDESTROY_LIVES("goal.blockdestroy.bdlives", 1, "BlockDestroy"),
 
         GOAL_CHECKPOINTS_CLAIMRANGE("goal.checkpoints.cpclaimrange", 5, "CheckPoints"),
@@ -202,15 +196,16 @@ public enum CFG {
         GOAL_DOM_CLAIMRANGE("goal.dom.claimrange", 3, "Domination"),
         GOAL_DOM_LIVES("goal.dom.dlives", 10, "Domination"),
         GOAL_DOM_ONLYWHENMORE("goal.dom.onlywhenmore", false, "Domination"),
-        GOAL_DOM_PARTICLECIRCLE("goal.dom.particlecircle", false, "Domination"),
+        GOAL_DOM_PARTICLECIRCLE("goal.dom.particlecircle", true, "Domination"),
         GOAL_DOM_TICKINTERVAL("goal.dom.tickinterval", 60, "Domination"),
         GOAL_DOM_TICKREWARD("goal.dom.tickreward", 1, "Domination"),
 
-        GOAL_FLAGS_FLAGTYPE("goal.flags.flagType", "WOOL", false, "Flags"),
+        GOAL_FLAGS_FLAGTYPE("goal.flags.flagType", Material.WHITE_WOOL, "Flags"),
         GOAL_FLAGS_LIVES("goal.flags.flives", 3, "Flags"),
         GOAL_FLAGS_MUSTBESAFE("goal.flags.mustBeSafe", true, "Flags"),
         GOAL_FLAGS_WOOLFLAGHEAD("goal.flags.woolFlagHead", true, "Flags"),
         GOAL_FLAGS_FLAGEFFECT("goal.flags.effect", "none", "Flags"),
+        GOAL_FLAGS_ALTERONCATCH("goal.flags.alterOnCatch", true, "Flags"),
 
         GOAL_FOOD_FMAXITEMS("goal.food.fmaxitems", 50, "Food"),
         GOAL_FOOD_FPLAYERITEMS("goal.food.fplayeritems", 10, "Food"),
@@ -224,10 +219,17 @@ public enum CFG {
 
         GOAL_LLIVES_LIVES("goal.liberation.llives", 3, "Liberation"),
         GOAL_PDM_LIVES("goal.playerdm.pdlives", 3, "PlayerDeathMatch"),
+
+        GOAL_PFLAGS_FLAGTYPE("goal.physicalflags.flagType", Material.WHITE_WOOL, "PhysicalFlags"),
+        GOAL_PFLAGS_LIVES("goal.physicalflags.flives", 3, "PhysicalFlags"),
+        GOAL_PFLAGS_MUSTBESAFE("goal.physicalflags.mustBeSafe", true, "PhysicalFlags"),
+        GOAL_PFLAGS_WOOLFLAGHEAD("goal.physicalflags.woolFlagHead", true, "PhysicalFlags"),
+        GOAL_PFLAGS_FLAGEFFECT("goal.physicalflags.effect", "none", "PhysicalFlags"),
+
         GOAL_PLIVES_LIVES("goal.playerlives.plives", 3, "PlayerLives"),
         GOAL_TANK_LIVES("goal.tank.tlives", 1, "Tank"),
         GOAL_TDC_LIVES("goal.teamdc.tdclives", 10, "TeamDeathConfirm"),
-        GOAL_TDC_ITEM("goal.teamdc.tdcitem", "WOOL", false, "TeamDeathConfirm"),
+        GOAL_TDC_ITEM("goal.teamdc.tdcitem", Material.WHITE_WOOL, "TeamDeathConfirm"),
         GOAL_TDM_LIVES("goal.teamdm.tdlives", 10, "TeamDeathMatch"),
         GOAL_TDM_SUICIDESCORE("goal.teamdm.suicideScore", false, "TeamDeathMatch"),
         GOAL_TLIVES_LIVES("goal.teamlives.tlives", 10, "TeamLives"),
@@ -252,11 +254,6 @@ public enum CFG {
         GOAL_PLAYERKILLREWARD_GRADUALLYDOWN("goal.playerkillreward.graduallyDown", false, "PlayerKillReward"),
         GOAL_PLAYERKILLREWARD_ONLYGIVE("goal.playerkillreward.onlyGive", false, "PlayerKillReward"),
 
-        GOAL_RESCUE_RESCUETYPE("goal.rescue.flagType", "VILLAGER", "Rescue"),
-        GOAL_RESCUE_LIVES("goal.rescue.rlives", 1, "Rescue"),
-        GOAL_RESCUE_MUSTBESAFE("goal.rescue.mustBeSafe", true, "Rescue"),
-        GOAL_RESCUE_RESCUEEFFECT("goal.rescue.effect", "none", "Rescue"),
-
         // -----------
 
         MODULES_AFTERMATCH_AFTERMATCH("modules.aftermatch.aftermatch", "off", "AfterMatch"),
@@ -304,13 +301,34 @@ public enum CFG {
         MODULES_BLOCKRESTORE_RESTORECHESTS("modules.blockrestore.restorechests", false, "BlockRestore"),
 
         MODULES_BLOCKDISSOLVE_CALCOFFSET("modules.blockdissolve.calcoffset", 0.333, "BlockDissolve"),
-        MODULES_BLOCKDISSOLVE_MATERIALS("modules.blockdissolve.materials", "SNOW,WOOL", true, "BlockDissolve"),
+        MODULES_BLOCKDISSOLVE_MATERIALS("modules.blockdissolve.materials", new ItemStack[]{
+                new ItemStack(Material.SNOW_BLOCK, 1),
+
+                new ItemStack(Material.BLACK_WOOL, 1),
+                new ItemStack(Material.BLUE_WOOL, 1),
+                new ItemStack(Material.CYAN_WOOL, 1),
+                new ItemStack(Material.BROWN_WOOL, 1),
+
+                new ItemStack(Material.GRAY_WOOL, 1),
+                new ItemStack(Material.GREEN_WOOL, 1),
+                new ItemStack(Material.LIGHT_BLUE_WOOL, 1),
+                new ItemStack(Material.LIGHT_GRAY_WOOL, 1),
+
+                new ItemStack(Material.LIME_WOOL, 1),
+                new ItemStack(Material.MAGENTA_WOOL, 1),
+                new ItemStack(Material.ORANGE_WOOL, 1),
+                new ItemStack(Material.RED_WOOL, 1),
+
+                new ItemStack(Material.PINK_WOOL, 1),
+                new ItemStack(Material.PURPLE_WOOL, 1),
+                new ItemStack(Material.YELLOW_WOOL, 1),
+                new ItemStack(Material.WHITE_WOOL, 1)}, "BlockDissolve"),
         MODULES_BLOCKDISSOLVE_STARTSECONDS("modules.blockdissolve.startseconds", 10, "BlockDissolve"),
         MODULES_BLOCKDISSOLVE_TICKS("modules.blockdissolve.ticks", 40, "BlockDissolve"),
 
         MODULES_CHESTFILLER_CHESTLOCATION("modules.chestfiller.chestlocation", "none", "ChestFiller"),
         MODULES_CHESTFILLER_CLEAR("modules.chestfiller.clear", false, "ChestFiller"),
-        MODULES_CHESTFILLER_ITEMS("modules.chestfiller.cfitems", "1", true, "ChestFiller"),
+        MODULES_CHESTFILLER_ITEMS("modules.chestfiller.cfitems", new ItemStack[]{new ItemStack(Material.STONE)}, "ChestFiller"),
         MODULES_CHESTFILLER_MAXITEMS("modules.chestfiller.cfmaxitems", 5, "ChestFiller"),
         MODULES_CHESTFILLER_MINITEMS("modules.chestfiller.cfminitems", 0, "ChestFiller"),
 
@@ -323,7 +341,7 @@ public enum CFG {
         MODULES_FIXINVENTORYLOSS_INVENTORY("modules.fixinventoryloss.inventory", false, "FixInventoryLoss"),
 
         MODULES_ITEMS_INTERVAL("modules.items.interval", 0, "Items"),
-        MODULES_ITEMS_ITEMS("modules.items.items", "none", true, "Items"),
+        MODULES_ITEMS_ITEMS("modules.items.items", new ItemStack[0], "Items"),
 
         MODULES_RESPAWNRELAY_INTERVAL("modules.respawnrelay.respawnseconds", 10, "RespawnRelay"),
         MODULES_RESPAWNRELAY_CHOOSESPAWN("modules.respawnrelay.choosespawn", false, "RespawnRelay"),
@@ -341,6 +359,11 @@ public enum CFG {
         MODULES_POWERUPS_DROPSPAWN("modules.powerups.dropspawn", false, "Powerups"),
         MODULES_POWERUPS_USAGE("modules.powerups.usage", "off", "Powerups"),
 
+        MODULES_PROJECTILES_SNOWBALL("modules.projectiles.snowball", true, "Projectiles"),
+        MODULES_PROJECTILES_EGG("modules.projectiles.egg", true, "Projectiles"),
+        MODULES_PROJECTILES_FISHHOOK("modules.projectiles.fishHook", false, "Projectiles"),
+        MODULES_PROJECTILES_ENDERPEARL("modules.projectiles.enderPearl", false, "Projectiles"),
+
         MODULES_SKINS_VANILLA("modules.skins.vanilla", false, "Skins"),
 
         MODULES_SPECIALJOIN_SHOWPLAYERS("modules.specialjoin.showplayers", true, "SpecialJoin"),
@@ -386,7 +409,7 @@ public enum CFG {
         MODULES_VAULT_REWARD_TRIGGER("modules.vault.reward.trigger", 0.0d, "Vault"),
         MODULES_VAULT_REWARD_WIN("modules.vault.reward.playerWin", 0.0d, "Vault"),
 
-        MODULES_WALLS_MATERIAL("modules.walls.wallmaterial", "SAND", false, "Walls"),
+        MODULES_WALLS_MATERIAL("modules.walls.wallmaterial", Material.SAND, "Walls"),
         MODULES_WALLS_SCOREBOARDCOUNTDOWN("modules.walls.scoreboardcountdown", false, "Walls"),
         MODULES_WALLS_SECONDS("modules.walls.wallseconds", 300, "Walls"),
 
@@ -438,10 +461,17 @@ public static CFG getByNode(final String node) {
             module = source;
         }
 
-        CFG(final String node, final String value, final boolean multiple, final String source) {
+        CFG(final String node, final ItemStack[] value, final String source) {
             this.node = node;
-            this.value = value;
-            type = multiple ? "items" : "material";
+            this.value = getSerializableItemStacks(value);
+            type = "items";
+            module = source;
+        }
+
+        CFG(final String node, final Material value, final String source) {
+            this.node = node;
+            this.value = value.name();
+            type = "material";
             module = source;
         }
 
@@ -502,7 +532,7 @@ public String getType() {
         }
 
         public String getModule() {
-            return module;
+            return this.module;
         }
 
         public boolean hasModule() {
@@ -736,16 +766,19 @@ public Material getMaterial(final CFG cfg, final Material def) {
     }
 
     public ItemStack[] getItems(final CFG cfg) {
-        return getItems(cfg, StringParser.getItemStacksFromString((String) cfg.getValue()));
-    }
-
-    public ItemStack[] getItems(final CFG cfg, final ItemStack[] def) {
         final String path = cfg.getNode();
-        final String result = strings.get(path);
-        if (result == null || "none".equals(result)) {
-            return def;
+        try {
+            String test = this.cfg.getString(path);
+            if ("none".equalsIgnoreCase(test)) {
+                return new ItemStack[0];
+            }
+        } catch (Exception e) {
+        }
+        try {
+            return getItemStacksFromConfig(this.cfg.getList(path));
+        } catch (NullPointerException e) {
+            return new ItemStack[0];
         }
-        return StringParser.getItemStacksFromString(result);
     }
 
     public Set getKeys(final String path) {
@@ -757,6 +790,10 @@ public Set getKeys(final String path) {
         return section.getKeys(false);
     }
 
+    public List getStringList(final CFG cfg) {
+        return this.getStringList(cfg.getNode(), null);
+    }
+
     public List getStringList(final String path, final List def) {
         if (cfg.get(path) == null) {
             return def == null ? new LinkedList() : def;
@@ -765,6 +802,7 @@ public List getStringList(final String path, final List def) {
         return cfg.getStringList(path);
     }
 
+
     // /////////////////////////////////////////////////////////////////////////
     // //
     // MUTATORS //
@@ -906,7 +944,13 @@ public static ArenaRegion parseRegion(final Arena arena,
         final Integer flags = parseInteger(parts[8]);
         final Integer prots = parseInteger(parts[9]);
 
-        if (Bukkit.getWorld(parts[0]) == null || x1 == null || y1 == null
+        if (Bukkit.getWorld(parts[0]) == null) {
+            PVPArena.instance.getLogger().severe(String.format("%s caused an error while loading region %s",
+                    arena.getName(), regionName));
+            throw new IllegalArgumentException(String.format("World %s not recognized. Is it loaded ?", parts[0]));
+        }
+
+        if (x1 == null || y1 == null
                 || z1 == null || x2 == null || y2 == null || z2 == null
                 || flags == null || prots == null) {
             PVPArena.instance.getLogger().severe(arena.getName() + " caused an error while loading region " + regionName);
diff --git a/src/net/slipcor/pvparena/core/Debug.java b/src/net/slipcor/pvparena/core/Debug.java
index 9924601ef..e9136a088 100644
--- a/src/net/slipcor/pvparena/core/Debug.java
+++ b/src/net/slipcor/pvparena/core/Debug.java
@@ -13,8 +13,8 @@
 import java.io.StringWriter;
 import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.logging.*;
 import java.util.logging.Formatter;
+import java.util.logging.*;
 
 
 /**
diff --git a/src/net/slipcor/pvparena/core/ItemStackUtils.java b/src/net/slipcor/pvparena/core/ItemStackUtils.java
new file mode 100644
index 000000000..87cef1960
--- /dev/null
+++ b/src/net/slipcor/pvparena/core/ItemStackUtils.java
@@ -0,0 +1,189 @@
+package net.slipcor.pvparena.core;
+
+import net.slipcor.pvparena.PVPArena;
+import org.bukkit.Bukkit;
+import org.bukkit.Color;
+import org.bukkit.Material;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.LeatherArmorMeta;
+import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.potion.PotionEffect;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.bukkit.configuration.serialization.ConfigurationSerialization.deserializeObject;
+
+public class ItemStackUtils  {
+    /**
+     * List of "meta-type" config keys which can be drop
+     */
+    private enum HandledMetaType {
+        POTION, ENCHANTED, BOOK_SIGNED, BOOK, BANNER, MAP, FIREWORK, LEATHER_ARMOR, UNSPECIFIC
+    }
+
+    private static boolean isAnHandledMetaType(String metaTypeString) {
+        try{
+            HandledMetaType.valueOf(metaTypeString);
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Check the meta keyset to deduce which meta-type is associated
+     * @param keySet The meta config node values
+     * @return Right "meta-type" value
+     */
+    private static HandledMetaType getRightMetaType(Collection keySet) {
+        if(keySet.contains("potion-type") || keySet.contains("custom-effects")) {
+            return HandledMetaType.POTION;
+        }
+        if(keySet.contains("stored-enchants")) {
+            return HandledMetaType.ENCHANTED;
+        }
+        if(keySet.contains("map-id")) {
+            return HandledMetaType.MAP;
+        }
+        if(keySet.contains("patterns")) {
+            return HandledMetaType.BANNER;
+        }
+        if(keySet.contains("pages")) {
+            if(keySet.contains("author")) {
+                return HandledMetaType.BOOK_SIGNED;
+            }
+            return HandledMetaType.BOOK;
+        }
+        if(keySet.contains("firework-effects")) {
+            return HandledMetaType.FIREWORK;
+        }
+        if(keySet.contains("color")) {
+            return HandledMetaType.LEATHER_ARMOR;
+        }
+        return HandledMetaType.UNSPECIFIC;
+    }
+
+
+    /**
+     * Pseudo-serializer which creates a map version of objects in order to prettify the yaml after serialization
+     * @param itemStack A bukkit ItemStack object
+     * @return Serializable map
+     */
+    public static Map getItemStackMap(ItemStack itemStack) {
+        Map result = new LinkedHashMap<>();
+        result.put("type", itemStack.getType().name());
+        if (itemStack.getAmount() != 1) {
+            result.put("amount", itemStack.getAmount());
+        }
+
+        ItemMeta meta = itemStack.getItemMeta();
+        if (!Bukkit.getItemFactory().equals(meta, null)) {
+            Map metaMap = new LinkedHashMap<>(meta.serialize());
+            if(isAnHandledMetaType(metaMap.get("meta-type").toString())) {
+                metaMap.remove("meta-type");
+
+                // Simplify leather armor colors
+                if(meta instanceof LeatherArmorMeta) {
+                    metaMap.put("color", ((LeatherArmorMeta) meta).getColor().serialize());
+                }
+
+                // Simplify custom potion effects
+                if(meta instanceof PotionMeta) {
+                    PotionMeta potionMeta = (PotionMeta) meta;
+
+                    if(potionMeta.hasCustomEffects()) {
+                        List> customEffectMeta = potionMeta.getCustomEffects().stream()
+                                .map(PotionEffect::serialize)
+                                .collect(Collectors.toList());
+                        metaMap.put("custom-effects", customEffectMeta);
+
+                        if(potionMeta.hasColor()) {
+                            metaMap.put("custom-color", potionMeta.getColor().serialize());
+                        }
+                    }
+                }
+            }
+            result.put("meta", metaMap);
+        }
+
+        return result;
+    }
+
+    /**
+     * A custom deserializer which convert prettified yaml config to bukkit objects
+     * Mainly based on the bukkit ConfigurationSerializable deserializer
+     * @param args An ItemStack config node
+     * @return A bukkit ItemStack object
+     */
+    private static ItemStack deserialize(Map args) {
+        int amount = 1;
+
+        Material type = Material.getMaterial((String) args.get("type"));
+
+        if(type != null) {
+            if (args.containsKey("amount")) {
+                amount = ((Number) args.get("amount")).intValue();
+            }
+
+            ItemStack result = new ItemStack(type, amount);
+
+            if (args.containsKey("meta")) {
+                Map metaMap = new LinkedHashMap<>((Map) args.get("meta"));
+                metaMap.put("==", ItemMeta.class.getSimpleName());
+                if(!metaMap.containsKey("meta-type")) {
+                    metaMap.put("meta-type", getRightMetaType(metaMap.keySet()).name());
+
+                    //Simplify Leather armor colors
+                    if(metaMap.containsKey("color")) {
+                        Color color = Color.deserialize((Map) metaMap.get("color"));
+                        metaMap.put("color", color);
+                    }
+
+                    // Simplify custom potion effects
+                    if(metaMap.containsKey("custom-effects")) {
+                        List effectList = ((List) metaMap.get("custom-effects")).stream()
+                                .map(serializedEffect -> new PotionEffect((Map) serializedEffect))
+                                .collect(Collectors.toList());
+
+                        metaMap.put("custom-effects", effectList);
+
+                        // handle custom-color only if item is a custom potion
+                        if(metaMap.containsKey("custom-color")) {
+                            Color color = Color.deserialize((Map) metaMap.get("custom-color"));
+                            metaMap.put("custom-color", color);
+                        }
+                    }
+                }
+
+
+                ConfigurationSerializable raw = deserializeObject(metaMap);
+                if (raw instanceof ItemMeta) {
+                    result.setItemMeta((ItemMeta) raw);
+                }
+            }
+            return result;
+        } else {
+            PVPArena.instance.getLogger().warning("Invalid item type : " + args.get("type"));
+            return new ItemStack(Material.AIR);
+        }
+    }
+
+    /**
+     * Deserialize an ItemSTack list config node
+     * @param mapList List of ItemStack nodes
+     * @return An array of bukkit ItemStack objects
+     */
+    public static ItemStack[] getItemStacksFromConfig(List mapList) {
+        ItemStack[] result = new ItemStack[mapList.size()];
+        for(int i = 0; i < mapList.size(); i++) {
+            result[i] = deserialize((Map) mapList.get(i));
+        }
+        return result;
+    }
+}
diff --git a/src/net/slipcor/pvparena/core/Language.java b/src/net/slipcor/pvparena/core/Language.java
index 147377e4b..f48c20caa 100644
--- a/src/net/slipcor/pvparena/core/Language.java
+++ b/src/net/slipcor/pvparena/core/Language.java
@@ -86,6 +86,10 @@ public enum MSG {
         DEATHCAUSE_SUICIDE("nulang.deathcause.SUICIDE", "self"),
         DEATHCAUSE_THORNS("nulang.deathcause.THORNS", "thorns"),
         DEATHCAUSE_VOID("nulang.deathcause.VOID", "the Void"),
+        DEATHCAUSE_FALLING_BLOCK("nulang.deathcause.FALLING_BLOCK", "a falling block"),
+        DEATHCAUSE_HOT_FLOOR("nulang.deathcause.HOT_FLOOR", "a magma block"),
+        DEATHCAUSE_CRAMMING("nulang.deathcause.CRAMMING", "a collision surplus"),
+        DEATHCAUSE_DRAGON_BREATH("nulang.deathcause.DRAGON_BREATH", "dragon breath"),
 
         DEATHCAUSE_CREEPER("nulang.deathcause.CREEPER", "a creeper"),
         DEATHCAUSE_SKELETON("nulang.deathcause.SKELETON", "a skeleton"),
@@ -180,7 +184,6 @@ public enum MSG {
         ERROR_NOPERM_C_ENABLE("nulang.nopermto.cmds.enable", "use the enable command"),
         ERROR_NOPERM_C_GAMEMODE("nulang.nopermto.cmds.gamemode", "use the gamemode command"),
         ERROR_NOPERM_C_GOAL("nulang.nopermto.cmds.goal", "use the goal command"),
-        ERROR_NOPERM_C_INSTALL("nulang.nopermto.cmds.install", "use the install command"),
         ERROR_NOPERM_C_PLAYERCLASS("nulang.nopermto.cmds.playerclass", "use the playerclass command"),
         ERROR_NOPERM_C_PLAYERJOIN("nulang.nopermto.cmds.playerjoin", "use the playerjoin command"),
         ERROR_NOPERM_C_PROTECTION("nulang.nopermto.cmds.protection", "use the protection command"),
@@ -201,8 +204,7 @@ public enum MSG {
         ERROR_NOPERM_C_TELEPORT("nulang.nopermto.cmds.teleport", "use the teleport command"),
         ERROR_NOPERM_C_TEMPLATE("nulang.nopermto.cmds.template", "use the template command"),
         ERROR_NOPERM_C_TOGGLEMOD("nulang.nopermto.cmds.togglemod", "use the togglemod command"),
-        ERROR_NOPERM_C_UNINSTALL("nulang.nopermto.cmds.uninstall", "use the uninstall command"),
-        ERROR_NOPERM_C_UPDATE("nulang.nopermto.cmds.update", "use the update command"),
+        ERROR_NOPERM_C_MODULES("nulang.nopermto.cmds.uninstall", "use the modules command"),
         ERROR_NOPERM_C_WHITELIST("nulang.nopermto.cmds.whitelist", "use the whitelist command"),
         ERROR_NOPERM_C_ARENACLASS("nulang.nopermto.cmds.arenaclass", "use the arenaclass command"),
         ERROR_NOPERM_C_CHAT("nulang.nopermto.cmds.chat", "use the chat command"),
@@ -322,10 +324,6 @@ public enum MSG {
 
         LOG_PLUGIN_DISABLED("nulang.log.plugindisabled", "disabled (version %1%)"),
         LOG_PLUGIN_ENABLED("nulang.log.pluginenabled", "enabled (version %1%)"),
-        LOG_TRACKER_DISABLED("nulang.log.trickerdisabled", "Plugin tracking disabled. See you soon?"),
-        LOG_TRACKER_ENABLED("nulang.log.trackingenabled", "Plugin tracking enabled. Set 'tracker: false' inside the main config to disable."),
-        LOG_UPDATE_DISABLED("nulang.log.updatedisabled", "Updates deactivated. Please check dev.bukkit for updates."),
-        LOG_UPDATE_ENABLED("nulang.log.updateenabled", "Checking for updates..."),
         LOG_WARNING("nulang.log.warning", "%1%"),
 
         MESSAGES_TOARENA("nulang.messages.toArena", "You are now talking to the arena!"),
@@ -410,6 +408,7 @@ public enum MSG {
         SET_DONE("nulang.set.done", "&a%1%&r set to &e%2%&r!"),
         SET_HELP("nulang.set.help", "Use /pa {arenaname} set [page] to get a node list."),
         SET_UNKNOWN("nulang.set.unknown", "Unknown node: &e%1%&r!"),
+        SET_ITEMS_NOT("nulang.set.items_not", "Please use either hand or inventory to set an item node!"),
 
         SETOWNER_DONE("nulang.setowner.done", "&a%1%&r is now owner of arena &a%2%&r!"),
 
@@ -427,15 +426,15 @@ public enum MSG {
         STATS_HEAD("nulang.stats.head", "Statistics TOP %1% (%2%)"),
         STATS_TYPENOTFOUND("nulang.stats.typenotfound", "Statistics type not found! Valid values: &e%1%&r"),
 
-        STATTYPE_DAMAGE("nulang.stattype.DAMAGE", StatisticsManager.type.DAMAGE.getName()),
-        STATTYPE_DAMAGETAKE("nulang.stattype.DAMAGETAKE", StatisticsManager.type.DAMAGETAKE.getName()),
-        STATTYPE_DEATHS("nulang.stattype.DEATHS", StatisticsManager.type.DEATHS.getName()),
-        STATTYPE_KILLS("nulang.stattype.KILLS", StatisticsManager.type.KILLS.getName()),
-        STATTYPE_LOSSES("nulang.stattype.LOSSES", StatisticsManager.type.LOSSES.getName()),
-        STATTYPE_MAXDAMAGE("nulang.stattype.MAXDAMAGE", StatisticsManager.type.MAXDAMAGE.getName()),
-        STATTYPE_MAXDAMAGETAKE("nulang.stattype.MAXDAMAGETAKE", StatisticsManager.type.MAXDAMAGETAKE.getName()),
-        STATTYPE_NULL("nulang.stattype.NULL", StatisticsManager.type.NULL.getName()),
-        STATTYPE_WINS("nulang.stattype.WINS", StatisticsManager.type.WINS.getName()),
+        STATTYPE_DAMAGE("nulang.stattype.DAMAGE", StatisticsManager.Type.DAMAGE.getName()),
+        STATTYPE_DAMAGETAKE("nulang.stattype.DAMAGETAKE", StatisticsManager.Type.DAMAGETAKE.getName()),
+        STATTYPE_DEATHS("nulang.stattype.DEATHS", StatisticsManager.Type.DEATHS.getName()),
+        STATTYPE_KILLS("nulang.stattype.KILLS", StatisticsManager.Type.KILLS.getName()),
+        STATTYPE_LOSSES("nulang.stattype.LOSSES", StatisticsManager.Type.LOSSES.getName()),
+        STATTYPE_MAXDAMAGE("nulang.stattype.MAXDAMAGE", StatisticsManager.Type.MAXDAMAGE.getName()),
+        STATTYPE_MAXDAMAGETAKE("nulang.stattype.MAXDAMAGETAKE", StatisticsManager.Type.MAXDAMAGETAKE.getName()),
+        STATTYPE_NULL("nulang.stattype.NULL", StatisticsManager.Type.NULL.getName()),
+        STATTYPE_WINS("nulang.stattype.WINS", StatisticsManager.Type.WINS.getName()),
 
         TEAM_HAS_WON("nulang.team.haswon", "Team %1%&r are the Champions!"),
         TEAM_READY("nulang.team.ready", "Team %1%&r is ready!"),
@@ -462,6 +461,13 @@ public enum MSG {
         TOGGLEMOD_NOTICE("nulang.togglemod.notice", "&cYou activated a module that requires a BATTLE region! Type: &r/pvparena [arena] !rt [region] BATTLE"),
 
         UNINSTALL_DONE("nulang.uninstall.done", "Uninstalled: &a%1%&r"),
+        UPDATER_PLUGIN("nulang.updater.plugin", "PVP Arena"),
+        UPDATER_MODULES("nulang.updater.modules", "PVP Arena modules pack"),
+        UPDATER_ANNOUNCE("nulang.updater.announce", "%1% %2% is now available ! Your version: %3%"),
+        UPDATER_SUCCESS("nulang.updater.success", "%1% has been updated to %2%."),
+        UPDATER_RESTART("nulang.updater.restart", "Restart your server to apply update."),
+        UPDATER_DOWNLOADING("nulang.updater.downloading", "Downloading %1%..."),
+        UPDATER_DOWNLOAD_ERROR("nulang.updater.downloaderror", "Error while downloading %1%"),
 
         WHITELIST_ADDED("nulang.whitelist.added", "Added &a%1%&r to &e%2%&r whitelist!"),
         WHITELIST_ALLCLEARED("nulang.whitelist.allcleared", "All whitelists cleared!"),
@@ -470,18 +476,6 @@ public enum MSG {
         WHITELIST_REMOVED("nulang.whitelist.removed", "Removed &a%1%&r from &e%2%&r whitelist!"),
         WHITELIST_SHOW("nulang.whitelist.show", "Whitelist &e%1%&r:"),
 
-        GOAL_BEACONS_CLAIMING("nulang.goal.beacons.claiming", "&eTeam %1% is claiming the beacon!"),
-        GOAL_BEACONS_CLAIMED("nulang.goal.beacons.claimed", "&eTeam %1% has claimed the beacon!"),
-        GOAL_BEACONS_CLAIMED_REMAINING("nulang.goal.beacons.claimed_remaining", "&eTeam %1% has claimed the beacon! %2% claims remaining!"),
-        GOAL_BEACONS_SCORE("nulang.goal.beacons.score", "&eTeam %1% scored %2% points by holding the beacon!"),
-        GOAL_BEACONS_CHANGED("nulang.goal.beacons.changed", "&eA new beacon has been activated!"),
-        GOAL_BEACONS_CONTESTING("nulang.goal.beacons.contesting", "&eThe beacon claimed by team %1% is being contested!"),
-        GOAL_BEACONS_UNCLAIMING("nulang.goal.beacons.unclaiming", "&eThe beacon claimed by team %1% is being unclaimed!"),
-        GOAL_BEACONS_UNCLAIMINGBY("nulang.goal.beacons.unclaimingby", "&eThe beacon claimed by team %1% is being unclaimed by team %2%!"),
-        GOAL_BEACONS_SET("nulang.goal.beacons.set", "Beacon set: %1%"),
-        GOAL_BEACONS_SETDONE("nulang.goal.beacons.setdone", "Beacon setting mode deactivated."),
-        GOAL_BEACONS_TOSET("nulang.goal.beacons.toset", "Beacon setting mode activated. Hit the glass blocks, then use the command again to save!"),
-
         GOAL_BLOCKDESTROY_TYPESET("nulang.goal.blockdestroy.typeset", "Blocktype set to: &e%1%"),
         GOAL_BLOCKDESTROY_SCORE("lang.goal.blockdestroy.score", "%1% destroyed the block of team %2%! Remaining destructions: %3%"),
         GOAL_BLOCKDESTROY_SET("nulang.goal.blockdestroy.setflag", "Block set: %1%"),
@@ -490,6 +484,8 @@ public enum MSG {
         GOAL_CHECKPOINTS_SCORE("nulang.goal.checkpoints.score", "%1% &ereached checkpoint #%2%!"),
         GOAL_CHECKPOINTS_YOUMISSED("nulang.goal.checkpoints.youmissed", "You missed checkpoint #%1%! This is #%2%"),
 
+        GOAL_DOMINATION_BOSSBAR_CLAIMING("nulang.goal.dom.bossbar_claiming", "Claiming..."),
+        GOAL_DOMINATION_BOSSBAR_UNCLAIMING("nulang.goal.dom.bossbar_claiming", "Unclaiming..."),
         GOAL_DOMINATION_CLAIMING("nulang.goal.dom.claiming", "&eTeam %1% is claiming a flag!"),
         GOAL_DOMINATION_CLAIMED("nulang.goal.dom.claimed", "&eTeam %1% has claimed a flag!"),
         GOAL_DOMINATION_SCORE("nulang.goal.dom.score", "&eTeam %1% scored %2% points by holding a flag!"),
@@ -535,8 +531,9 @@ public enum MSG {
         GOAL_SABOTAGE_IGNITED("nulang.goal.sabotage.tntignite", "%1% ignited the TNT of team %2%!"),
         GOAL_SABOTAGE_SETTNT("nulang.goal.sabotage.set", "TNT set: %1%"),
         GOAL_SABOTAGE_TOSETTNT("nulang.goal.sabotage.toset", "TNT to set: %1%"),
-        GOAL_SABOTAGE_YOUCANNOTSELFDESTROY("nulang.goal.sabotage.youcannotselfdestroy", "You can not ignite your own TNT!'"),
-        GOAL_SABOTAGE_YOUTNT("nulang.goal.sabotage.youtnt", "You now carry the sabotage materials!'"),
+        GOAL_SABOTAGE_NOSELFDESTROY("nulang.goal.sabotage.noselfdestroy", "You can not ignite your own TNT!"),
+        GOAL_SABOTAGE_NOTGOODITEM("nulang.goal.sabotage.notgooditem", "You need sabotage tool to ignite the TNT."),
+        GOAL_SABOTAGE_YOUTNT("nulang.goal.sabotage.youtnt", "You now carry the sabotage tool."),
 
         GOAL_TANK_TANKDOWN("nulang.goal.tank.tankdown", "The tank is down!"),
         GOAL_TANK_TANKMODE("nulang.goal.tank.tankmode", "TANK MODE! Everyone kill %1%, the tank!"),
@@ -560,15 +557,6 @@ public enum MSG {
 
         GOAL_PILLARS_MSG_SCORE("nulang.goal.pillars.msg.score", "%1% scored %2% points."),
 
-
-        GOAL_RESCUE_BROUGHTHOME("nulang.goal.rescue.flaghomeleft", "%1% brought home the hostage of team %2%! Rescues remaining: %3%"),
-        GOAL_RESCUE_DROPPED("nulang.goal.rescue.flagsave", "%1% dropped the hostage of team %2%!"),
-        GOAL_RESCUE_GRABBED("nulang.goal.rescue.flaggrab", "%1% grabbed the hostage of team %2%!"),
-        GOAL_RESCUE_NOTSAFE("nulang.goal.rescue.flagnotsafe", "Your hostage is taken! Cannot bring back an enemy hostage!'"),
-        GOAL_RESCUE_SET("nulang.goal.rescue.setflag", "Rescue set: %1%"),
-        GOAL_RESCUE_TOSET("nulang.goal.rescue.tosetflag", "Rescue to set: %1%"),
-        GOAL_RESCUE_TYPESET("nulang.goal.rescue.typeset", "Hostage type set to: &e%1%"),
-
         // -----------------------------------------------
 
         MODULE_AFTERMATCH_STARTING("nulang.mod.aftermatch.aftermatch", "The aftermatch has begun!"),
@@ -643,6 +631,7 @@ public enum MSG {
         MODULE_LATELOUNGE_POSITION("nulang.mod.latelounge.llposition", "You are in queue. Position: #%1%"),
         MODULE_LATELOUNGE_REJOIN("nulang.mod.latelounge.llrejoin", "Ready check has caught you not being able to join. Rejoin when you can!"),
         MODULE_LATELOUNGE_WAIT("nulang.mod.latelounge.llwait", "Arena will be starting soon, please wait!"),
+        MODULE_LATELOUNGE_LEAVE("nulang.mod.latelounge.llleave", "You have left the queue of the %1% arena."),
 
         MODULE_PLAYERFINDER_NEAR("nulang.mod.playerfinder.near", "Nearest player: %1% blocks!"),
         MODULE_PLAYERFINDER_POINT("nulang.mod.playerfinder.point", "Compass pointing to nearest player!"),
@@ -663,6 +652,17 @@ public enum MSG {
         MODULE_SPECIALJOIN_START("nulang.mod.specialjoin.start", "Setting join block!"),
         MODULE_SPECIALJOIN_STOP("nulang.mod.specialjoin.stop", "Aborted join block selection!"),
 
+        MODULE_SQUADS_NOSQUAD("nulang.mod.squads.nosquad", "No squads loaded! Add some: /pa [arena] !sq add [name]"),
+        MODULE_SQUADS_LISTHEAD("nulang.mod.squads.listhead", "Squads for arena &b%1%"),
+        MODULE_SQUADS_LISTITEM("nulang.mod.squads.listitem", "Squad %1% (max: %2%) %3%"),
+        MODULE_SQUADS_ADDED("nulang.mod.squads.added", "Squad %1% has been added"),
+        MODULE_SQUADS_SET("nulang.mod.squads.set", "Squad %1% has been set"),
+        MODULE_SQUADS_REMOVED("nulang.mod.squads.removed", "Squad %1% has been removed"),
+        MODULE_SQUADS_NOTEXIST("nulang.mod.squads.notexist", "Squad %1% doesn't exist!"),
+        MODULE_SQUADS_ERROR("nulang.mod.squads.error", "Error while editing squads, syntax is not correct!"),
+        MODULE_SQUADS_FULL("nulang.mod.squads.full", "This squad is full!"),
+        MODULE_SQUADS_HELP("nulang.mod.squads.help", "/pa !sq | show the arena squads\n/pa !sq add [name] [limit] | add squad with player limit (set to 0 for no limit)\n/pa !sq set [name] [limit] | set player limit for squad\n/pa !sq remove [name] | remove squad [name]"),
+
         MODULE_STARTFREEZE_ANNOUNCE("nulang.mod.startfreeze.announce", "The game will start in %1% seconds!"),
 
         MODULE_TEMPPERMS_NOPERMS("nulang.mod.tempperms.noperms", "Permissions plugin not found, defaulting to OP."),
diff --git a/src/net/slipcor/pvparena/core/StringParser.java b/src/net/slipcor/pvparena/core/StringParser.java
index cf0b19ce9..e786b150b 100644
--- a/src/net/slipcor/pvparena/core/StringParser.java
+++ b/src/net/slipcor/pvparena/core/StringParser.java
@@ -1,23 +1,13 @@
 package net.slipcor.pvparena.core;
 
-import net.slipcor.pvparena.PVPArena;
 import org.bukkit.ChatColor;
-import org.bukkit.Color;
-import org.bukkit.DyeColor;
-import org.bukkit.Material;
 import org.bukkit.block.BlockFace;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.EntityType;
 import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.*;
-import org.bukkit.material.Dye;
-import org.bukkit.material.Wool;
-import org.bukkit.potion.PotionData;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.potion.PotionType;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * 
@@ -31,9 +21,6 @@
  */
 
 public final class StringParser {
-    private static final String SAFE_BREAK = "";
-    private static final String SAFE_PAGE_BREAK = "";
-    private static final String SAFE_LORE_BREAK = "";
 
     private static final Debug DEBUG = new Debug(17);
 
@@ -45,31 +32,6 @@ private StringParser() {
     public static final Set negative = new HashSet<>(Arrays.asList(
             "no", "off", "false", "0"));
 
-    private static String codeCharacters(final String string, final boolean forward) {
-        final Map findReplace = new HashMap<>();
-        String result = string;
-        if (forward) {
-            findReplace.put(":", "<>");
-            findReplace.put("~", "<>");
-            findReplace.put("|", "<>");
-            findReplace.put(",", "<>");
-            findReplace.put(ChatColor.COLOR_CHAR + "", "&");
-        } else {
-            findReplace.put("<>", ":");
-            findReplace.put("<>", "~");
-            findReplace.put("<>", "|");
-            findReplace.put("<>", ",");
-            result = ChatColor.translateAlternateColorCodes('&', result);
-            result = ChatColor.translateAlternateColorCodes('?', result);
-        }
-
-        for (final Map.Entry stringStringEntry : findReplace.entrySet()) {
-            result = result.replace(stringStringEntry.getKey(), stringStringEntry.getValue());
-        }
-
-        return result;
-    }
-
     public static String colorize(final String string) {
         return ChatColor.translateAlternateColorCodes('&', string)
                 .replace("&&", "&").replace("%%&%%", "&");
@@ -129,548 +91,7 @@ public static String colorVar(final String string) {
      * @return a colored string
      */
     public static String colorVar(final String string, final boolean value) {
-        return (value ? ChatColor.GREEN.toString() : ChatColor.RED.toString()) + string
-                + ChatColor.WHITE;
-    }
-
-    /**
-     * calculate a WOOL byte from a color enum
-     *
-     * @param color the string to parse
-     * @return the color short
-     */
-    public static byte getColorDataFromENUM(final String color) {
-
-        String wool = getWoolEnumFromChatColorEnum(color);
-        if (wool == null) {
-            wool = color;
-        }
-        /*
-		 * DyeColor supports: WHITE, ORANGE, MAGENTA, LIGHT_BLUE, YELLOW, LIME,
-		 * PINK, GRAY, SILVER, CYAN, PURPLE, BLUE, BROWN, GREEN, RED, BLACK;
-		 */
-
-        for (final DyeColor dc : DyeColor.values()) {
-            if (dc.name().equalsIgnoreCase(wool)) {
-                return (byte) (15 - dc.getDyeData());
-            }
-        }
-        PVPArena.instance.getLogger().warning("unknown color enum: " + wool);
-
-        return (byte) 0;
-    }
-
-    public static ChatColor getChatColorFromWoolEnum(final String color) {
-        return ChatColor.valueOf(parseDyeColorToChatColor(color, true));
-    }
-
-    /**
-     * construct an itemstack out of a string
-     *
-     * @param string the formatted string: [itemid/name][~[dmg]]~[data]:[amount]
-     * @return the itemstack
-     */
-    public static ItemStack getItemStackFromString(final String string) {
-        DEBUG.i("parsing itemstack string: " + string);
-
-        // [itemid/name]~[dmg]|[enchantmentID]~level:[amount]
-
-
-        String[] temp = string.split(":");
-
-        String prefix = null;
-
-        for (final String s : PVPArena.instance.getConfig().getStringList("materialprefixes")) {
-            if (string.startsWith(prefix+ ':')) {
-                prefix = s;
-                temp = string.substring(prefix.length()).split(":");
-            }
-        }
-
-        if (temp[0].startsWith("0>>O<<")) {
-            temp[0] = temp[0].substring(6);
-        }
-
-        String desc = null;
-        int amount = 1;
-        if (temp.length > 1) {
-            try {
-                amount = Integer.parseInt(temp[1]);
-            } catch (final NumberFormatException e) {
-                PVPArena.instance.getLogger().severe("Material error. Maybe add " + temp[0] + " to materialprefixes?");
-                return new ItemStack(Material.AIR);
-            }
-            if (temp.length > 2) {
-                desc = temp[2];
-            }
-        }
-
-        final Map enchants = new HashMap<>();
-        if (temp[0].contains("|")) {
-            DEBUG.i("trying to add enchantment");
-            final String[] temp2 = temp[0].split("\\|");
-            DEBUG.i("temp2 length: " + temp2.length);
-            temp[0] = temp2[0];
-
-            DEBUG.i("correcting item temp to " + temp[0]);
-
-            for (int i = 1; i < temp2.length; i++) {
-
-                final String strEnch = temp2[i];
-                if (strEnch.contains("~")) {
-                    final String[] arrEnch = strEnch.split("~");
-                    final Enchantment ench = Enchantment.getById(Integer
-                            .parseInt(arrEnch[0]));
-                    final Integer enchLevel = Integer.parseInt(arrEnch[1]);
-                    DEBUG.i("adding enchantment " + ench.getName() + " lvl "
-                            + enchLevel);
-                    enchants.put(ench, enchLevel);
-                }
-            }
-        }
-
-        temp = temp[0].split("~");
-
-        final Material mat = parseMat(prefix == null ? temp[0] : prefix + ':' + temp[0]);
-        if (mat != null) {
-            if (temp.length == 1) {
-                // [itemid/name]:[amount]
-
-                final ItemStack itemStack = new ItemStack(mat, amount);
-                for (final Map.Entry enchantmentIntegerEntry : enchants.entrySet()) {
-                    DEBUG.i("processing enchantment " + enchantmentIntegerEntry.getKey().getName());
-                    itemStack.addUnsafeEnchantment(enchantmentIntegerEntry.getKey(), enchantmentIntegerEntry.getValue());
-                }
-
-                if (desc != null) {
-                    final ItemMeta meta = itemStack.getItemMeta();
-                    meta.setDisplayName(codeCharacters(desc, false));
-                    itemStack.setItemMeta(meta);
-                }
-
-                return itemStack;
-            }
-            final short dmg = Short.parseShort(temp[1]);
-            if (temp.length == 2) {
-                // [itemid/name]~[dmg]:[amount]
-                final ItemStack itemStack = new ItemStack(mat, amount, dmg);
-                for (final Map.Entry enchantmentIntegerEntry : enchants.entrySet()) {
-                    itemStack.addUnsafeEnchantment(enchantmentIntegerEntry.getKey(), enchantmentIntegerEntry.getValue());
-                }
-
-                if (desc != null) {
-                    final ItemMeta meta = itemStack.getItemMeta();
-                    meta.setDisplayName(codeCharacters(desc, false));
-                    itemStack.setItemMeta(meta);
-                }
-
-                return itemStack;
-            }
-            // string: POTION~0~INVISIBILITYx0x300~Duration 15 seconds.:2:Stealth
-
-            // ---> split(":");
-
-            // temp[0] = POTION~0~INVISIBILITYx0x300~Duration 15 seconds.
-            // temp[1] = 2
-            // temp[2] = Stealth
-
-            // ---> split("~");
-
-            // temp[0] = POTION
-            // temp[1] = 0
-            // temp[2] = INVISIBILITYx0x300
-            // temp[3] = Duration 15 seconds.
-
-            final int location;
-
-            if (temp.length > 3 && temp[3].contains(SAFE_LORE_BREAK)) {
-                location = 3;
-            } else {
-                location = 2;
-            }
-
-            final String[] dataSplit = temp[location].split(SAFE_LORE_BREAK);
-            String data = dataSplit[0];
-            if (temp[2].contains(SAFE_BREAK)) {
-                if (hasPotionMeta(mat)) {
-                    data = temp[2];
-                } else {
-                    data = temp[2].split(SAFE_BREAK)[0];
-                }
-            }
-
-            if (data.equals("")) {
-                // Data is messed up, let's try to fix it!
-
-                if (mat == Material.INK_SACK || mat == Material.WOOL) {
-                    data = temp[2]; // 2 or 3 definately is set as data, should work!
-                }
-            }
-
-            if (mat == Material.WRITTEN_BOOK) {
-                data = temp[2];
-            }
-
-            /**
-             *
-             private static final String SAFE_BREAK = "";
-             private static final String SAFE_PAGE_BREAK = "";
-             private static final String SAFE_LORE_BREAK = "";
-             *
-             */
-
-            final String lore = dataSplit.length > 1 ? dataSplit[1] : null;
-
-            if (temp.length >= 3) {
-                // [itemid/name]~[dmg]~[data]:[amount]
-                final ItemStack itemStack = new ItemStack(mat, amount, dmg);
-
-
-                if (desc != null) {
-                    final ItemMeta meta = itemStack.getItemMeta();
-                    meta.setDisplayName(codeCharacters(desc, false));
-                    itemStack.setItemMeta(meta);
-                }
-
-                if (mat == Material.INK_SACK) {
-                    try {
-                        itemStack.setData(new Dye(Byte.parseByte(data)));
-                    } catch (final Exception e) {
-                        DEBUG.i(
-                                "invalid dye data: " + data);
-                        return itemStack;
-                    }
-                } else if (mat == Material.WOOL) {
-                    try {
-                        itemStack.setData(new Wool(Byte.parseByte(data)));
-                    } catch (final Exception e) {
-                        PVPArena.instance.getLogger().warning(
-                                "invalid wool data: " + data);
-                        return itemStack;
-                    }
-                } else if (mat == Material.WRITTEN_BOOK
-                        || mat == Material.BOOK_AND_QUILL) {
-                    final BookMeta bookMeta = (BookMeta) itemStack.getItemMeta();
-                    try {
-                        final String[] outer = data.split(SAFE_BREAK);
-                        bookMeta.setAuthor(codeCharacters(outer[0], false));
-                        bookMeta.setTitle(codeCharacters(outer[1], false));
-                        final List pages = new ArrayList<>();
-                        final String[] inner = codeCharacters(outer[2], false).split(
-                                SAFE_PAGE_BREAK);
-                        Collections.addAll(pages, inner);
-                        bookMeta.setPages(pages);
-                        itemStack.setItemMeta(bookMeta);
-                    } catch (final Exception e) {
-                        PVPArena.instance.getLogger().warning(
-                                "invalid book data: " + data);
-                        return itemStack;
-                    }
-                } else if (itemStack.getType().name().startsWith("LEATHER_")) {
-                    try {
-                        final LeatherArmorMeta leatherMeta = (LeatherArmorMeta) itemStack
-                                .getItemMeta();
-                        leatherMeta.setColor(Color.fromRGB(Integer.parseInt(data)));
-                        itemStack.setItemMeta(leatherMeta);
-                    } catch (final Exception e) {
-                        DEBUG.i(
-                                "invalid leather data: " + data);
-                        return itemStack;
-                    }
-                } else if (itemStack.getType() == Material.SKULL_ITEM) {
-                    try {
-                        final SkullMeta skullMeta = (SkullMeta) itemStack.getItemMeta();
-                        skullMeta.setOwner(data);
-                        itemStack.setItemMeta(skullMeta);
-                    } catch (final Exception e) {
-                        PVPArena.instance.getLogger().warning(
-                                "invalid skull data: " + data);
-                        return itemStack;
-                    }
-                } else if (hasPotionMeta(itemStack)) {
-                    // data = NAMEx1x100NAMEx2x100
-                    // 1.9+ = NEWNAMEXtrueXtrueNAMEx1x100NAMEx2x100
-                    try {
-                        final PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
-
-                        final String[] defs = data.split(SAFE_BREAK);
-
-                        defs: for (final String def : defs) {
-                            if (def.contains("X")) {
-                                String[] vals = def.split("X");
-                                for (PotionType type : PotionType.values()) {
-                                    if (type == null || type.getEffectType() == null) {
-                                        continue;
-                                    }
-                                    if (vals[0].equals(type.getEffectType().getName())) {
-                                        PotionData pData = new PotionData(type, StringParser.positive.contains(vals[1]), StringParser.positive.contains(vals[2]));
-                                        potionMeta.setBasePotionData(pData);
-                                        continue defs;
-                                    }
-                                }
-                                PVPArena.instance.getLogger().warning("Invalid base potion data: "+def);
-                            }
-                            final String[] vals = def.split("x");
-                            potionMeta.addCustomEffect(
-                                    new PotionEffect(
-                                            PotionEffectType.getByName(vals[0]),
-                                            Integer.parseInt(vals[2]),
-                                            Integer.parseInt(vals[1])), true);
-                        }
-
-                        if (lore != null
-                                && !(mat == Material.WRITTEN_BOOK || mat == Material.BOOK_AND_QUILL)) {
-                            final List lLore = new ArrayList<>();
-                            for (final String line : lore.split(SAFE_BREAK)) {
-                                lLore.add(codeCharacters(line, false));
-                            }
-                            potionMeta.setLore(lLore);
-                        }
-
-                        itemStack.setItemMeta(potionMeta);
-                    } catch (final Exception e) {
-                        PVPArena.instance.getLogger().warning(
-                                "invalid potion data: " + data);
-                        e.printStackTrace();
-                        return itemStack;
-                    }
-                } else if (itemStack.getType() == Material.MONSTER_EGG) {
-                    try {
-                        final SpawnEggMeta meta = (SpawnEggMeta) itemStack.getItemMeta();
-                        meta.setSpawnedType(EntityType.fromName(data));
-                        itemStack.setItemMeta(meta);
-                    } catch (final Exception e) {
-                        PVPArena.instance.getLogger().warning(
-                                "invalid spawn egg data: " + data);
-                        return itemStack;
-                    }
-                } else {
-                    DEBUG.i("data not available for: " + mat.name());
-                }
-
-                if (lore != null
-                        && !(mat == Material.WRITTEN_BOOK || mat == Material.BOOK_AND_QUILL)) {
-                    final List lLore = new ArrayList<>();
-                    for (final String line : lore.split(SAFE_BREAK)) {
-                        lLore.add(codeCharacters(line, false));
-                    }
-                    final ItemMeta itemMeta = itemStack.getItemMeta();
-                    itemMeta.setLore(lLore);
-                    itemStack.setItemMeta(itemMeta);
-                }
-
-                for (final Map.Entry enchantmentIntegerEntry : enchants.entrySet()) {
-                    itemStack.addUnsafeEnchantment(enchantmentIntegerEntry.getKey(), enchantmentIntegerEntry.getValue());
-                }
-
-                return itemStack;
-            }
-        }
-        return null;
-    }
-
-    private static boolean hasPotionMeta(ItemStack itemStack) {
-        if (itemStack == null) {
-            return false;
-        }
-        if (itemStack.getItemMeta() instanceof PotionMeta) {
-            return true;
-        }
-        Material mat = itemStack.getType();
-        return hasPotionMeta(mat);
-    }
-
-    private static boolean hasPotionMeta(Material mat) {
-        return mat == Material.POTION || mat == Material.SPLASH_POTION || mat == Material.LINGERING_POTION || mat == Material.TIPPED_ARROW;
-    }
-
-    public static ItemStack[] getItemStacksFromString(final String string) {
-        if ("none".equals(string)) {
-            return new ItemStack[0];
-        }
-
-        final String[] args = string.split(",");
-
-        final ItemStack[] result = new ItemStack[args.length];
-
-        int pos = 0;
-
-        for (final String s : args) {
-            result[pos++] = getItemStackFromString(s);
-        }
-
-        return result;
-    }
-
-    public static String getStringFromItemStacks(final ItemStack[] isItems) {
-        if (isItems == null) {
-            return "AIR";
-        }
-        final String[] split = new String[isItems.length];
-
-        int pos = 0;
-
-        for (final ItemStack is : isItems) {
-            split[pos++] = getStringFromItemStack(is);
-        }
-
-        return joinArray(trimAir(split), ",");
-    }
-
-    private static String[] trimAir(final String[] sArray) {
-        final List list = new ArrayList<>();
-        for (final String item : sArray) {
-            if ("AIR".equals(item)) {
-                continue;
-            }
-            list.add(item);
-        }
-
-        if (list.size() < 1) {
-            return new String[]{"AIR"};
-        }
-
-        final String[] result = new String[list.size()];
-        int pos = 0;
-        for (final String item : list) {
-            result[pos++] = item;
-        }
-
-        return result;
-    }
-
-    public static String getStringFromItemStack(final ItemStack itemStack) {
-        if (itemStack == null || itemStack.getType() == Material.AIR) {
-            return "AIR";
-        }
-        final StringBuilder temp = new StringBuilder(itemStack.getType().name());
-        boolean durability = false;
-        if (itemStack.getDurability() != 0) {
-            temp.append('~');
-            temp.append(itemStack.getDurability());
-            durability = true;
-        }
-        if (itemStack.getType() == Material.INK_SACK || itemStack.getType() == Material.WOOL) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            temp.append('~');
-            temp.append(itemStack.getData().getData());
-        } else if (itemStack.getType() == Material.WRITTEN_BOOK
-                || itemStack.getType() == Material.BOOK_AND_QUILL) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            final BookMeta bookMeta = (BookMeta) itemStack.getItemMeta();
-            if (bookMeta != null && bookMeta.getAuthor() != null && bookMeta.getTitle() != null
-                    && bookMeta.getPages() != null) {
-                temp.append('~');
-                temp.append(codeCharacters(bookMeta.getAuthor(), true));
-                temp.append(SAFE_BREAK);
-                temp.append(codeCharacters(bookMeta.getTitle(), true));
-                temp.append(SAFE_BREAK);
-                temp.append(codeCharacters(
-                        joinArray(bookMeta.getPages().toArray(),
-                                SAFE_PAGE_BREAK), true));
-
-            }
-        } else if (itemStack.getType().name().startsWith("LEATHER_")) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            final LeatherArmorMeta leatherMeta = (LeatherArmorMeta) itemStack.getItemMeta();
-            temp.append('~');
-            temp.append(leatherMeta.getColor().asRGB());
-        } else if (itemStack.getType() == Material.SKULL_ITEM) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            final SkullMeta skullMeta = (SkullMeta) itemStack.getItemMeta();
-            temp.append('~');
-            temp.append(skullMeta.getOwner());
-        } else if (hasPotionMeta(itemStack)) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            final PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
-            temp.append('~');
-            PotionData pData = potionMeta.getBasePotionData();
-            try {
-                temp.append(pData.getType().getEffectType().getName()).append('X').append(pData.isExtended()).append('X').append(pData.isUpgraded());
-                temp.append(SAFE_BREAK);
-            } catch (Exception e) {
-            }
-            for (final PotionEffect pe : potionMeta.getCustomEffects()) {
-                temp.append(pe.getType().getName()).append('x').append(pe.getAmplifier()).append('x').append(pe.getDuration());
-                temp.append(SAFE_BREAK);
-            }
-        } else if (itemStack.getType() == Material.MONSTER_EGG){
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-            temp.append('~');
-            final SpawnEggMeta meta = (SpawnEggMeta) itemStack.getItemMeta();
-            if (meta != null && meta.getSpawnedType() != null && meta.getSpawnedType().name() != null) {
-                temp.append(meta.getSpawnedType().name());
-            }
-        }
-
-        if (itemStack.hasItemMeta() && itemStack.getItemMeta().hasLore()) {
-            if (!durability) {
-                temp.append('~');
-                temp.append(itemStack.getDurability());
-                durability = true;
-            }
-
-            temp.append('~');
-            temp.append(SAFE_LORE_BREAK);
-            temp.append(codeCharacters(
-                    joinArray(itemStack.getItemMeta().getLore()
-                            .toArray(), SAFE_BREAK), true));
-        }
-        Map enchants = null;
-        try {
-            enchants = itemStack.getEnchantments();
-        } catch (Exception e) {
-            // Caused by: java.lang.NullPointerException: null key in entry: null=1
-        }
-
-        if (enchants != null && !enchants.isEmpty()) {
-            for (final Map.Entry enchantmentIntegerEntry : enchants.entrySet()) {
-                temp.append('|');
-                temp.append(enchantmentIntegerEntry.getKey().getId());
-                temp.append('~');
-                temp.append(enchantmentIntegerEntry.getValue());
-            }
-        }
-
-        if (itemStack.getAmount() > 1 || itemStack.getItemMeta().hasDisplayName()) {
-            temp.append(':');
-            temp.append(itemStack.getAmount());
-        }
-
-        if (itemStack.getItemMeta().hasDisplayName()) {
-            temp.append(':');
-            temp.append(codeCharacters(itemStack.getItemMeta().getDisplayName(), true));
-        }
-
-        return temp.toString().replace(ChatColor.COLOR_CHAR, '&');
-    }
-
-    private static String getWoolEnumFromChatColorEnum(final String color) {
-        return parseDyeColorToChatColor(color, false);
+        return (value ? ChatColor.GREEN.toString() : ChatColor.RED.toString()) + string + ChatColor.WHITE;
     }
 
     public static String joinArray(final Object[] array, final String glue) {
@@ -709,64 +130,6 @@ public static String joinSet(final Set set, final String glue) {
         return result.substring(glue.length());
     }
 
-    private static String parseDyeColorToChatColor(final String color, final boolean forward) {
-
-        /**
-         * wool colors: ORANGE, MAGENTA, LIGHT_BLUE, LIME, PINK, GRAY, SILVER,
-         * PURPLE, BLUE, GREEN, RED, CYAN;
-         *
-         * chat colors: GOLD, LIGHT_PURPLE, BLUE, GREEN, RED, DARK_GRAY, GRAY,
-         * DARK_PURPLE, DARK_BLUE, DARK_GREEN, DARK_RED, DARK_AQUA
-         *
-         *
-         *
-         * both colors (ignore): WHITE, YELLOW, BLACK
-         *
-         * colors not being able to parse:
-         *
-         * chat-AQUA, wool-brown
-         */
-        final String[] wool = {"ORANGE", "MAGENTA", "LIGHT_BLUE",
-                "LIME", "PINK", "GRAY", "SILVER", "PURPLE", "BLUE",
-                "GREEN", "RED", "CYAN"};
-        final String[] chat = {"GOLD", "LIGHT_PURPLE", "BLUE",
-                "GREEN", "RED", "DARK_GRAY", "GRAY", "DARK_PURPLE", "DARK_BLUE",
-                "DARK_GREEN", "DARK_RED", "DARK_AQUA"};
-
-        if (forward) {
-            for (int i = 0; i < wool.length; i++) {
-                if (color.equals(wool[i])) {
-                    return chat[i];
-                }
-            }
-        } else {
-
-            for (int i = 0; i < chat.length; i++) {
-                if (color.equals(chat[i])) {
-                    return wool[i];
-                }
-            }
-        }
-
-        return color;
-    }
-
-    /**
-     * retrieve a material from a string
-     *
-     * @param string the string to parse
-     * @return the material
-     */
-    private static Material parseMat(final String string) {
-        DEBUG.i("parsing material: " + string);
-        Material mat = Material.getMaterial(string);
-        if (mat == null) {
-            PVPArena.instance.getLogger().warning(
-                    "unrecognized material: " + string);
-        }
-        return mat;
-    }
-
     public static String[] shiftArrayBy(final String[] args, final int offset) {
         final String[] newArgs = new String[args.length - offset];
         System.arraycopy(args, offset, newArgs, 0, args.length - offset);
@@ -825,4 +188,22 @@ public static String[] splitForScoreBoard(String key) {
         split[pos] = buffer.toString();
         return split;
     }
+
+    public static String getItems(ItemStack[] items) {
+        if (items == null || items.length < 1) {
+            return "none";
+        }
+        StringBuffer buff = new StringBuffer();
+        for (ItemStack item : items) {
+            buff.append(", ");
+            try {
+                buff.append(item.getType());
+                buff.append('x');
+                buff.append(item.getAmount());
+            } catch (Exception e) {
+                buff.append("!error!");
+            }
+        }
+        return buff.substring(2);
+    }
 }
diff --git a/src/net/slipcor/pvparena/core/Tracker.java b/src/net/slipcor/pvparena/core/Tracker.java
deleted file mode 100644
index 51afaee9d..000000000
--- a/src/net/slipcor/pvparena/core/Tracker.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package net.slipcor.pvparena.core;
-
-import net.slipcor.pvparena.PVPArena;
-import net.slipcor.pvparena.core.Language.MSG;
-import org.bukkit.Bukkit;
-import org.bukkit.scheduler.BukkitTask;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLEncoder;
-
-/**
- * 
Tracker class
- *

- * phones home to www.slipcor.net, saving server IP and PVP Arena version - * - * @author slipcor - * @version v0.9.5 - */ - -public class Tracker implements Runnable { - private static BukkitTask timerTask; - private static final Debug debug = new Debug(18); - - /** - * call home to save the server/plugin state - */ - private void callHome() { - if (!PVPArena.instance.getConfig().getBoolean("tracker", true)) { - stop(); - return; - } - debug.i("calling home..."); - - String url = null; - try { - url = String - .format("http://www.slipcor.net/stats/call.php?port=%s&name=%s&version=%s", - PVPArena.instance.getServer().getPort(), - URLEncoder.encode(PVPArena.instance.getDescription().getName(), "UTF-8"), - URLEncoder.encode(PVPArena.instance.getDescription().getVersion(), "UTF-8")); - } catch (final UnsupportedEncodingException e) { - e.printStackTrace(); - } - - try { - new URL(url).openConnection().getInputStream(); - } catch (final Exception e) { - PVPArena.instance.getLogger().warning("Error while connecting to www.slipcor.net"); - return; - } - debug.i("successfully called home!"); - } - - @Override - public void run() { - callHome(); - } - - /** - * start tracking - */ - public void start() { - Language.logInfo(MSG.LOG_TRACKER_ENABLED); - - timerTask = Bukkit.getScheduler().runTaskTimerAsynchronously(PVPArena.instance, this, - 0L, 72000L); - } - - /** - * stop tracking - */ - public static void stop() { - Language.logInfo(MSG.LOG_TRACKER_DISABLED); - if (timerTask != null) { - try { - timerTask.cancel(); - timerTask = null; - } catch (Exception e) { - - } - } - } -} diff --git a/src/net/slipcor/pvparena/core/Updater.java b/src/net/slipcor/pvparena/core/Updater.java deleted file mode 100644 index 9f1048824..000000000 --- a/src/net/slipcor/pvparena/core/Updater.java +++ /dev/null @@ -1,477 +0,0 @@ -package net.slipcor.pvparena.core; - -import net.slipcor.pvparena.PVPArena; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.io.*; -import java.net.URL; -import java.net.URLConnection; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class Updater extends Thread { - private final boolean files; - - private final UpdateMode mode; - private final UpdateType type; - - private final Plugin plugin; - private final File file; - - private final int major; - private final int minor; - - private final List instances = new ArrayList<>(); - - protected enum UpdateMode { - OFF, ANNOUNCE, DOWNLOAD, BOTH; - - public static UpdateMode getBySetting(final String setting) { - final String lcSetting = setting.toLowerCase(); - if (lcSetting.contains("ann")) { - return ANNOUNCE; - } - if (lcSetting.contains("down") || lcSetting.contains("load")) { - return DOWNLOAD; - } - if ("both".equals(lcSetting)) { - return BOTH; - } - return OFF; - } - } - - protected enum UpdateType { - ALPHA, BETA, RELEASE; - - public static UpdateType getBySetting(final String setting) { - if ("beta".equalsIgnoreCase(setting)) { - return BETA; - } - if ("alpha".equalsIgnoreCase(setting)) { - return ALPHA; - } - return RELEASE; - } - } - - public Updater(final Plugin plugin, final File file) { - super(); - - String version = Bukkit.getServer().getBukkitVersion(); - - String[] chunks; - try { - chunks = version.split("-")[0].split("\\."); - } catch (Exception e) { - chunks = new String[]{"1","11"}; - } - int a,b; - try { - a = Integer.parseInt(chunks[0]); - } catch (Exception e) { - a = 1; - } - major = a; - try { - b = Integer.parseInt(chunks[1]); - } catch (Exception e) { - b = 9; - } - minor = b; - - this.plugin = plugin; - this.file = file; - this.files = plugin.getConfig().getBoolean("update.modules"); - - mode = UpdateMode.getBySetting(plugin.getConfig().getString("update.mode", "both")); - - if (mode == UpdateMode.OFF) { - type = UpdateType.RELEASE; - } else { - instances.clear(); - type = UpdateType.getBySetting(plugin.getConfig().getString("update.type", "beta")); - instances.add(new UpdateInstance("pvparena", false)); - if (files) { - final File zipFolder = new File(plugin.getDataFolder(), "files"); - zipFolder.mkdir(); - if (type == UpdateType.RELEASE) { - instances.add(new UpdateInstance("pafiles", true)); - } else { - instances.add(new UpdateInstance("pa_goals", true)); - instances.add(new UpdateInstance("pa_mods", true)); - } - } - start(); - } - - if (plugin.getConfig().getBoolean("update.modules", true)) { - try { - final File destination = plugin.getDataFolder(); - if (!destination.exists()) { - destination.mkdirs(); - - } - - final File lib = new File(destination, "install.yml"); - - plugin.getLogger().info("Downloading module update file..."); - final URL url = new URL( - "http://pa.slipcor.net/getYML.php?major="+major+"&minor="+minor); - final ReadableByteChannel rbc = Channels.newChannel(url.openStream()); - final FileOutputStream output = new FileOutputStream(lib); - output.getChannel().transferFrom(rbc, 0, 1 << 24); - plugin.getLogger().info("Downloaded module update file"); - output.close(); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - - class UpdateInstance { - - - private byte updateDigit; - private String vOnline; - private String vThis; - private String pluginName; - private String url; - private final boolean zip; - - private boolean msg; - private boolean outdated; - - UpdateInstance(String checkName, boolean isZip) { - pluginName = checkName; - zip = isZip; - } - - /** - * calculate the message variables based on the versions - */ - private void calculateVersions() { - final String[] aOnline = vOnline.split("\\."); - final String[] aThis = vThis.split("\\."); - outdated = false; - - - for (int i = 0; i < aOnline.length && i < aThis.length; i++) { - try { - final int iOnline = Integer.parseInt(aOnline[i]); - final int iThis = Integer.parseInt(aThis[i]); - if (iOnline == iThis) { - msg = false; - continue; - } - msg = true; - outdated = iOnline > iThis; - updateDigit = (byte) i; - message(Bukkit.getConsoleSender(), this); - return; - } catch (final Exception e) { - calculateRadixString(aOnline[i], aThis[i], i); - return; - } - } - } - /** - * calculate a version part based on letters - * - * @param sOnline the online letter(s) - * @param sThis the local letter(s) - */ - private void calculateRadixString(final String sOnline, final String sThis, - final int pos) { - try { - final int iOnline = Integer.parseInt(sOnline, 36); - final int iThis = Integer.parseInt(sThis, 36); - if (iOnline == iThis) { - msg = false; - return; - } - msg = true; - outdated = iOnline > iThis; - updateDigit = (byte) pos; - message(Bukkit.getConsoleSender(), this); - } catch (final Exception e) { - e.printStackTrace(); - } - } - - /** - * colorize a given string based on a char - * - * @param string the string to colorize - * @return a colorized string - */ - private String colorize(final String string) { - final StringBuffer result; - if (updateDigit == 0) { - result = new StringBuffer(ChatColor.RED.toString()); - } else if (updateDigit == 1) { - result = new StringBuffer(ChatColor.GOLD.toString()); - } else if (updateDigit == 2) { - result = new StringBuffer(ChatColor.YELLOW.toString()); - } else if (updateDigit == 3) { - result = new StringBuffer(ChatColor.BLUE.toString()); - } else { - result = new StringBuffer(ChatColor.GREEN.toString()); - } - result.append(string); - result.append(ChatColor.WHITE); - return result.toString(); - } - - public void runMe() { - - try { - - String version = ""; - - URL website = new URL("http://pa.slipcor.net/versioncheck.php?plugin="+pluginName+"&type="+type.toString().toLowerCase()+"&major="+major+"&minor="+minor); - URLConnection connection = website.openConnection(); - BufferedReader in = new BufferedReader( - new InputStreamReader( - connection.getInputStream())); - String inputLine; - - while ((inputLine = in.readLine()) != null) { - version = inputLine; - break; - } - in.close(); - vOnline = version.replace("v", ""); - - url = "https://www.spigotmc.org/resources/pvp-arena.16584/"; - - website = new URL("http://pa.slipcor.net/versioncheck.php?plugin="+pluginName+"&link=true&type="+type.toString().toLowerCase()+"&major="+major+"&minor="+minor); - connection = website.openConnection(); - in = new BufferedReader( - new InputStreamReader( - connection.getInputStream())); - - while ((inputLine = in.readLine()) != null) { - url = inputLine; - break; - } - in.close(); - - vThis = plugin.getDescription().getVersion().replace("v", ""); - - calculateVersions(); - - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - - private void message(final CommandSender player, UpdateInstance instance) { - try { - if (!instance.msg) { - return; - } - - if (instance.outdated) { - if (!(player instanceof Player) && mode != UpdateMode.ANNOUNCE) { - // not only announce, download! - final File updateFolder = Bukkit.getServer().getUpdateFolderFile(); - if (!updateFolder.exists()) { - updateFolder.mkdirs(); - } - final File pluginFile = new File(updateFolder, file.getName()); - if (pluginFile.exists() && !instance.zip) { - pluginFile.delete(); - } - - final File zipFile = new File(updateFolder, plugin.getName() + "_files_"+instance.pluginName+".zip"); - if (zipFile.exists()) { - zipFile.delete(); - } - - if (instance.zip) { - downloadAndUnpack(instance.url, zipFile); - } else { - final URL url = new URL(instance.url); - final ReadableByteChannel rbc = Channels.newChannel(url.openStream()); - final FileOutputStream output = new FileOutputStream(pluginFile); - output.getChannel().transferFrom(rbc, 0, 1 << 24); - output.close(); - } - - } - - if (mode != UpdateMode.DOWNLOAD || (!( player instanceof Player))) { - - if (instance.zip) { - if (instances.size() > 2) { - player.sendMessage(instance.pluginName + " " + instance.colorize('v' + instance.vThis) - + ", an outdated version! Latest: " + ChatColor.COLOR_CHAR + 'a' + 'v' + instance.vOnline); - } else { - player.sendMessage("PVP Arena Files " + instance.colorize('v' + instance.vThis) - + ", an outdated version! Latest: " + ChatColor.COLOR_CHAR + 'a' + 'v' + instance.vOnline); - } - } else { - player.sendMessage("You are using " + instance.colorize('v' + instance.vThis) - + ", an outdated version! Latest: " + ChatColor.COLOR_CHAR + 'a' + 'v' + instance.vOnline); - if (files) { - if (instances.size() > 2) { - player.sendMessage("The results for the files are as follows:"); - } - } - } - } - - if (mode == UpdateMode.ANNOUNCE) { - player.sendMessage(instance.url); - } else { - if (!instance.zip) { - class RunLater implements Runnable { - @Override - public void run() { - player.sendMessage("The plugin has been updated, please restart the server!"); - } - } - Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RunLater(), 60L); - } - } - } else { - if (mode != UpdateMode.DOWNLOAD || (!( player instanceof Player))) { - if (instance.zip) { - if (instances.size() > 2) { - player.sendMessage(instance.pluginName + " " + instance.colorize('v' + instance.vThis) - + ", an experimental version! Latest stable: " + ChatColor.COLOR_CHAR + 'a' + 'v' - + instance.vOnline); - } else { - player.sendMessage("PVP Arena Files " + instance.colorize('v' + instance.vThis) - + ", an experimental version! Latest stable: " + ChatColor.COLOR_CHAR + 'a' + 'v' - + instance.vOnline); - } - } else { - player.sendMessage("You are using " + instance.colorize('v' + instance.vThis) - + ", an experimental version! Latest stable: " + ChatColor.COLOR_CHAR + 'a' + 'v' - + instance.vOnline); - if (files) { - if (instances.size() > 2) { - player.sendMessage("The results for the files are as follows:"); - } - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * message a player if the version is different - * - * @param player the player to message - */ - public void message(final CommandSender player) { - class DownloadLater implements Runnable { - - @Override - public void run() { - for (final UpdateInstance instance : instances) { - message(player, instance); - } - } - } - Bukkit.getScheduler().runTaskAsynchronously(plugin, new DownloadLater()); - } - - private void downloadAndUnpack(String zipURL, File zipFile) throws IOException { - final URL url2 = new URL(zipURL); - final ReadableByteChannel rbc2 = Channels.newChannel(url2.openStream()); - final FileOutputStream output2 = new FileOutputStream(zipFile); - output2.getChannel().transferFrom(rbc2, 0, 1 << 24); - output2.close(); - unzip(zipFile.getCanonicalPath()); - } - - @Override - public void run() { - if (mode == null || mode == UpdateMode.OFF) { - System.out.print(Language.parse(Language.MSG.LOG_UPDATE_DISABLED)); - return; - } - - System.out.print(Language.parse(Language.MSG.LOG_UPDATE_ENABLED)); - for (UpdateInstance instance : instances) { - instance.runMe(); - } - } - - /** - * Part of Zip-File-Extractor, modified by Gravity for use with Updater. - * - * @param file the location of the file to extract. - */ - private void unzip(final String file) { - try { - final File fSourceZip = new File(file); - final String zipPath = file.substring(0, file.length() - 4); - - final ZipFile zipFile = new ZipFile(fSourceZip); - - final Enumeration e = zipFile.entries(); - while (e.hasMoreElements()) { - final ZipEntry entry = e.nextElement(); - final File destinationFilePath = new File(zipPath, entry.getName()); - destinationFilePath.getParentFile().mkdirs(); - if (!entry.isDirectory()) { - final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); - int b; - final byte[] buffer = new byte[1024]; - final FileOutputStream fos = new FileOutputStream(destinationFilePath); - final BufferedOutputStream bos = new BufferedOutputStream(fos, 1024); - while ((b = bis.read(buffer, 0, 1024)) != -1) { - bos.write(buffer, 0, b); - } - bos.flush(); - bos.close(); - bis.close(); - final String name = destinationFilePath.getName(); - if (name.endsWith(".jar")) { - destinationFilePath.renameTo(new File(plugin.getDataFolder().getParent(), plugin.getDataFolder() + File.separator + "files" + File.separator + name)); - } - } - } - zipFile.close(); - - // Move any plugin data folders that were included to the right place, Bukkit won't do this for us. - for (final File dFile : new File(zipPath).listFiles()) { - if (dFile.isDirectory()) { - for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir - { - final File destFile = new File( - plugin.getDataFolder().getCanonicalPath() + - File.separator + "files" + - File.separator + cFile.getName()); - - destFile.delete(); - cFile.renameTo(destFile); - } - } - dFile.delete(); - } - new File(zipPath).delete(); - fSourceZip.delete(); - } catch (final IOException e) { - e.printStackTrace(); - } - new File(file).delete(); - } -} diff --git a/src/net/slipcor/pvparena/core/Utils.java b/src/net/slipcor/pvparena/core/Utils.java new file mode 100644 index 000000000..4b83ea775 --- /dev/null +++ b/src/net/slipcor/pvparena/core/Utils.java @@ -0,0 +1,43 @@ +package net.slipcor.pvparena.core; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static net.slipcor.pvparena.core.ItemStackUtils.getItemStackMap; + +public final class Utils { + private Utils() { + } + + public static List> getItemStacksFromMaterials(Material... mats) { + List> result = new ArrayList<>(); + for(Material mat : mats) { + result.add(getItemStackMap(new ItemStack(mat, mat == Material.ARROW ? 64 : 1))); + } + return result; + } + + + public static List> getSerializableItemStacks(ItemStack[] itemStacks) { + List> result = new ArrayList<>(); + for(ItemStack itemStack : itemStacks) { + if(itemStack != null) { + result.add(getItemStackMap(itemStack)); + } + } + return result; + } + + public static List> getSerializableItemStacks(ItemStack itemStack) { + return getSerializableItemStacks(new ItemStack[]{itemStack}); + } + + public static Location getCenteredLocation(Location loc) { + return new Location(loc.getWorld(), loc.getBlockX() + 0.5, loc.getBlockY() + 0.5, loc.getBlockZ() + 0.5); + } +} diff --git a/src/net/slipcor/pvparena/events/PAWinEvent.java b/src/net/slipcor/pvparena/events/PAWinEvent.java index 0f1071945..bae2662ce 100644 --- a/src/net/slipcor/pvparena/events/PAWinEvent.java +++ b/src/net/slipcor/pvparena/events/PAWinEvent.java @@ -4,6 +4,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.Arrays; @@ -24,9 +25,9 @@ public class PAWinEvent extends Event { private static final HandlerList HANDLERS = new HandlerList(); private final Arena arena; private final Player player; - private final List items; + private final List items; - public PAWinEvent(final Arena arena, final Player player, final String[] arrItems) { + public PAWinEvent(final Arena arena, final Player player, final ItemStack[] arrItems) { super(); this.arena = arena; this.player = player; @@ -38,7 +39,7 @@ public PAWinEvent(final Arena arena, final Player player, final String[] arrItem items.addAll(Arrays.asList(arrItems)); } - public void addItemString(final String item) { + public void addItemString(final ItemStack item) { items.add(item); } @@ -55,10 +56,10 @@ public HandlerList getHandlers() { return HANDLERS; } - public String[] getItems() { - final String[] output = new String[items.size()]; + public ItemStack[] getItems() { + final ItemStack[] output = new ItemStack[items.size()]; int pos = 0; - for (final String s : items) { + for (final ItemStack s : items) { output[pos++] = s; } return output; diff --git a/src/net/slipcor/pvparena/goals/GoalBlockDestroy.java b/src/net/slipcor/pvparena/goals/GoalBlockDestroy.java index fd7ff8c09..d941f51c5 100644 --- a/src/net/slipcor/pvparena/goals/GoalBlockDestroy.java +++ b/src/net/slipcor/pvparena/goals/GoalBlockDestroy.java @@ -11,11 +11,11 @@ import net.slipcor.pvparena.classes.PACheck; import net.slipcor.pvparena.commands.CommandTree; import net.slipcor.pvparena.commands.PAA_Region; +import net.slipcor.pvparena.core.ColorUtils; import net.slipcor.pvparena.core.Config.CFG; import net.slipcor.pvparena.core.Debug; import net.slipcor.pvparena.core.Language; import net.slipcor.pvparena.core.Language.MSG; -import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.events.PAGoalEvent; import net.slipcor.pvparena.loadables.ArenaGoal; import net.slipcor.pvparena.loadables.ArenaModuleManager; @@ -38,10 +38,7 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.util.Vector; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** *

@@ -96,9 +93,10 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Collections.singletonList("blocktype");
-        if (arena != null) {
-            for (final ArenaTeam team : arena.getTeams()) {
+        List result = new ArrayList<>();
+        if (this.arena != null) {
+            result.add("blocktype");
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 result.add(sTeam + "block");
             }
@@ -375,9 +373,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam()
-                            .getName()) ? getLifeMap().get(aPlayer
-                            .getArenaTeam().getName()) : 0));
+                    String.valueOf(getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
@@ -424,7 +421,7 @@ public void initate(final Player player) {
             final Set blocks = SpawnManager.getBlocksContaining(arena, "block");
 
             for (final PABlockLocation block : blocks) {
-                takeBlock(team.getColor().name(), block);
+                takeBlock(team.getColor(), block);
             }
         }
     }
@@ -449,7 +446,7 @@ public void parseStart() {
             final Set blocks = SpawnManager.getBlocksContaining(arena, "block");
 
             for (final PABlockLocation block : blocks) {
-                takeBlock(team.getColor().name(), block);
+                takeBlock(team.getColor(), block);
             }
         }
     }
@@ -496,20 +493,15 @@ public void setDefaults(final YamlConfiguration config) {
      * @param blockColor      the teamcolor to reset
      * @param paBlockLocation the location to take/reset
      */
-    void takeBlock(final String blockColor, final PABlockLocation paBlockLocation) {
+    void takeBlock(final ChatColor blockColor, final PABlockLocation paBlockLocation) {
         if (paBlockLocation == null) {
             return;
         }
-        if ("WOOL".equals(arena.getArenaConfig().getString(CFG.GOAL_BLOCKDESTROY_BLOCKTYPE))) {
+        Material blockDestroyType = Material.valueOf(arena.getArenaConfig().getString(CFG.GOAL_BLOCKDESTROY_BLOCKTYPE));
+        if (ColorUtils.isColorableMaterial(blockDestroyType)) {
             paBlockLocation.toLocation()
                     .getBlock()
-                    .setTypeIdAndData(
-                            Material.valueOf(
-                                    arena.getArenaConfig().getString(
-                                            CFG.GOAL_BLOCKDESTROY_BLOCKTYPE))
-                                    .getId(),
-                            StringParser.getColorDataFromENUM(blockColor),
-                            false);
+                    .setType(ColorUtils.getColoredMaterialFromChatColor(blockColor, blockDestroyType));
         } else {
             paBlockLocation.toLocation()
                     .getBlock()
@@ -547,17 +539,12 @@ public void unload(final Player player) {
     @EventHandler(priority = EventPriority.MONITOR)
     public void onBlockBreak(final BlockBreakEvent event) {
         final Player player = event.getPlayer();
-        if (!arena.hasPlayer(event.getPlayer())
-                || !event
-                .getBlock()
-                .getType()
-                .name()
-                .equals(arena.getArenaConfig().getString(
-                        CFG.GOAL_BLOCKDESTROY_BLOCKTYPE))) {
-
+        final Material blockToBreak = this.arena.getArenaConfig().getMaterial(CFG.GOAL_BLOCKDESTROY_BLOCKTYPE);
+        final Material brokenBlock = event.getBlock().getType();
+        if (!this.arena.hasPlayer(event.getPlayer()) || !ColorUtils.isSubType(brokenBlock, blockToBreak)) {
             arena.getDebugger().i("block destroy, ignoring", player);
             arena.getDebugger().i(String.valueOf(arena.hasPlayer(event.getPlayer())), player);
-            arena.getDebugger().i(event.getBlock().getType().name(), player);
+            arena.getDebugger().i(brokenBlock.name(), player);
             return;
         }
 
@@ -629,10 +616,10 @@ public void onBlockBreak(final BlockBreakEvent event) {
                         "score:" + player.getName() + ':' + aPlayer.getArenaTeam().getName() + ":1");
                 Bukkit.getPluginManager().callEvent(gEvent);
                 class RunLater implements Runnable {
-                    String localColor;
+                    ChatColor localColor;
                     PABlockLocation localLoc;
 
-                    RunLater(final String color, final PABlockLocation loc) {
+                    RunLater(final ChatColor color, final PABlockLocation loc) {
                         localColor = color;
                         localLoc = loc;
                     }
@@ -649,7 +636,7 @@ && getLifeMap().get(blockTeam) > SpawnManager.getBlocksStartingWith(arena, block
                     Bukkit.getScheduler().runTaskLater(
                             PVPArena.instance,
                             new RunLater(
-                                    arena.getTeam(blockTeam).getColor().name(),
+                                    arena.getTeam(blockTeam).getColor(),
                                     new PABlockLocation(event.getBlock().getLocation())), 5L);
                 }
                 reduceLivesCheckEndAndCommit(arena, blockTeam);
@@ -700,10 +687,10 @@ public void onEntityExplode(final EntityExplodeEvent event) {
                                 "[PVP Arena] team unknown/no lives: " + blockTeam);
                         e.printStackTrace();
                     }
-                    takeBlock(arena.getTeam(blockTeam).getColor().name(),
-                            pb.getLocation());
+                    takeBlock(arena.getTeam(blockTeam).getColor(), pb.getLocation());
 
                     reduceLivesCheckEndAndCommit(arena, blockTeam);
+                    break;
                 }
             }
         }
diff --git a/src/net/slipcor/pvparena/goals/GoalCheckPoints.java b/src/net/slipcor/pvparena/goals/GoalCheckPoints.java
index 4bb7a4bcd..4162d3068 100644
--- a/src/net/slipcor/pvparena/goals/GoalCheckPoints.java
+++ b/src/net/slipcor/pvparena/goals/GoalCheckPoints.java
@@ -24,6 +24,7 @@
 import org.bukkit.Location;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
 
 import java.util.*;
 
@@ -39,7 +40,7 @@ public class GoalCheckPoints extends ArenaGoal {
 
     public GoalCheckPoints() {
         super("CheckPoints");
-        debug = new Debug(99);
+        this.debug = new Debug(99);
     }
 
     @Override
@@ -51,7 +52,7 @@ public String version() {
 
     @Override
     public boolean allowsJoinInBattle() {
-        return arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
+        return this.arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
     }
 
     @Override
@@ -95,10 +96,10 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -115,7 +116,7 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
     private Set checkLocationPresentPlayers(final Location loc, final int distance) {
         final Set result = new HashSet<>();
 
-        for (final ArenaPlayer p : arena.getFighters()) {
+        for (final ArenaPlayer p : this.arena.getFighters()) {
             if (p.get().getLocation().getWorld().getName().equals(loc.getWorld().getName())) {
                 if (p.get().getLocation().distance(loc) > distance) {
                     continue;
@@ -128,21 +129,20 @@ private Set checkLocationPresentPlayers(final Location loc, final int di
         return result;
     }
 
-    void checkMove() {
+    private void checkMove() {
 
-        arena.getDebugger().i("------------------");
-        arena.getDebugger().i("  GCP checkMove();");
-        arena.getDebugger().i("------------------");
+        this.arena.getDebugger().i("------------------");
+        this.arena.getDebugger().i("  GCP checkMove();");
+        this.arena.getDebugger().i("------------------");
 
-        final int checkDistance = arena.getArenaConfig().getInt(
-                CFG.GOAL_DOM_CLAIMRANGE);
+        final int checkDistance = this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_CLAIMRANGE);
 
-        for (final PASpawn spawn : SpawnManager.getPASpawnsStartingWith(arena, "checkpoint")) {
+        for (final PASpawn spawn : SpawnManager.getPASpawnsStartingWith(this.arena, "checkpoint")) {
             final PALocation paLoc = spawn.getLocation();
-            final Set players = checkLocationPresentPlayers(paLoc.toLocation(),
+            final Set players = this.checkLocationPresentPlayers(paLoc.toLocation(),
                     checkDistance);
 
-            arena.getDebugger().i("players: " + StringParser.joinSet(players, ", "));
+            this.arena.getDebugger().i("players: " + StringParser.joinSet(players, ", "));
 
             // players now contains all players near the checkpoint
 
@@ -151,7 +151,7 @@ void checkMove() {
             }
             int value = Integer.parseInt(spawn.getName().substring(10));
             for (String playerName : players) {
-                maybeAddScoreAndBroadCast(playerName, value);
+                this.maybeAddScoreAndBroadCast(playerName, value);
             }
 
         }
@@ -159,22 +159,22 @@ void checkMove() {
 
     private void maybeAddScoreAndBroadCast(final String playerName, int checkpoint) {
 
-        if (!getLifeMap().containsKey(playerName)) {
+        if (!this.getLifeMap().containsKey(playerName)) {
             return;
         }
 
 
-        final int max = arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES);
+        final int max = this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES);
 
-        final int position = max - getLifeMap().get(playerName);
+        final int position = max - this.getLifeMap().get(playerName) + 1;
 
-        if (checkpoint <= position+1) {
-            arena.broadcast(Language.parse(arena, MSG.GOAL_CHECKPOINTS_SCORE,
-                    playerName, position+1 + "/" + max));
-            reduceLivesCheckEndAndCommit(arena, playerName);
+        if (checkpoint == position) {
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_CHECKPOINTS_SCORE,
+                    playerName, position + "/" + max));
+            this.reduceLivesCheckEndAndCommit(this.arena, playerName);
         } else if (checkpoint > position) {
-            arena.broadcast(Language.parse(arena, MSG.GOAL_CHECKPOINTS_YOUMISSED,
-                    String.valueOf(position + 1), String.valueOf(checkpoint)));
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_CHECKPOINTS_YOUMISSED,
+                    String.valueOf(position), String.valueOf(checkpoint)));
         }
 
     }
@@ -207,7 +207,7 @@ private void commitWin(final Arena arena, final String playerName) {
                     winner.getName()));
         }
 
-        getLifeMap().clear();
+        this.getLifeMap().clear();
         new EndRunnable(arena, arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
@@ -217,51 +217,59 @@ public void commitCommand(final CommandSender sender, final String[] args) {
         // 0 = checkpoint , [1 = number]
 
         if (!(sender instanceof Player)) {
-            Arena.pmsg(sender, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS));
+            Arena.pmsg(sender, Language.parse(this.arena, MSG.ERROR_ONLY_PLAYERS));
             return;
         }
 
         ArenaPlayer ap = ArenaPlayer.parsePlayer(sender.getName());
+        int cpLives = this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES);
 
-        if (args.length < 2 && arena.getFighters().contains(ap)) {
+        if (args.length < 2 && this.arena.getFighters().contains(ap)) {
             ap.setTelePass(true);
-            int value = arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES) - getLifeMap().get(ap.getName());
-            ap.get().teleport(SpawnManager.getSpawnByExactName(arena, "checkpoint"+value).toLocation());
+            int value = cpLives - this.getLifeMap().get(ap.getName());
+            if(value == 0) {
+                ap.get().teleport(SpawnManager.getSpawnByExactName(this.arena, "spawn").toLocation());
+            } else {
+                ap.get().teleport(SpawnManager.getSpawnByExactName(this.arena, "checkpoint"+value).toLocation());
+            }
             ap.setTelePass(false);
             return;
         }
 
-        if (!AbstractArenaCommand.argCountValid(sender, arena, args, new Integer[]{2})) {
+        if (!AbstractArenaCommand.argCountValid(sender, this.arena, args, new Integer[]{2})) {
             return;
         }
         int value;
         try {
             value = Integer.parseInt(args[1]);
-            Math.sqrt(value);
         } catch (Exception e) {
-            arena.msg(sender, Language.parse(arena, MSG.ERROR_NOT_NUMERIC, args[1]));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.ERROR_NOT_NUMERIC, args[1]));
             return;
         }
         Player player = (Player) sender;
         String spawnName = "checkpoint"+value;
-        arena.spawnSet(spawnName, new PALocation(player.getLocation()));
-        arena.msg(sender, Language.parse(arena, MSG.SPAWN_SET, spawnName));
+        if(value > 0 && value <= cpLives) {
+            this.arena.spawnSet(spawnName, new PALocation(player.getLocation()));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.SPAWN_SET, spawnName));
+        } else {
+            this.arena.msg(sender, Language.parse(this.arena, MSG.SPAWN_UNKNOWN, spawnName));
+        }
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[CP] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[CP] already ending");
             return;
         }
-        arena.getDebugger().i("[CP]");
+        this.arena.getDebugger().i("[CP]");
 
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
 
         ArenaPlayer ap = null;
 
-        for (ArenaPlayer aPlayer : arena.getFighters()) {
+        for (ArenaPlayer aPlayer : this.arena.getFighters()) {
             if (aPlayer.getStatus() == Status.FIGHT) {
                 ap = aPlayer;
                 break;
@@ -270,30 +278,29 @@ public void commitEnd(final boolean force) {
 
         if (ap != null && !force) {
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.PLAYER_HAS_WON, ap.getName()), "END");
+                    this.arena,
+                    Language.parse(this.arena, MSG.PLAYER_HAS_WON, ap.getName()), "END");
 
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.PLAYER_HAS_WON, ap.getName()), "WINNER");
-            arena.broadcast(Language.parse(arena, MSG.PLAYER_HAS_WON, ap.getName()));
+                    this.arena,
+                    Language.parse(this.arena, MSG.PLAYER_HAS_WON, ap.getName()), "WINNER");
+            this.arena.broadcast(Language.parse(this.arena, MSG.PLAYER_HAS_WON, ap.getName()));
         }
 
-        if (ArenaModuleManager.commitEnd(arena, ap.getArenaTeam())) {
+        if (ArenaModuleManager.commitEnd(this.arena, ap.getArenaTeam())) {
             return;
         }
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
-                CFG.TIME_ENDCOUNTDOWN));
+        new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public void displayInfo(final CommandSender sender) {
         sender.sendMessage("needed points: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES));
+                this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES));
         sender.sendMessage("claim range: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_CLAIMRANGE));
+                this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_CLAIMRANGE));
         sender.sendMessage("tick interval (ticks): " +
-                arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_TICKINTERVAL));
+                this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_TICKINTERVAL));
     }
 
     @Override
@@ -301,9 +308,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam()
-                            .getName()) ? getLifeMap().get(aPlayer
-                            .getArenaTeam().getName()) : 0));
+                    String.valueOf(this.getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
@@ -313,8 +319,8 @@ public boolean hasSpawn(final String string) {
         if (string.startsWith("checkpoint") || string.startsWith("spawn")) {
             return true;
         }
-        if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-            for (final ArenaClass aClass : arena.getClasses()) {
+        if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+            for (final ArenaClass aClass : this.arena.getClasses()) {
                 if (string.toLowerCase().contains(aClass.getName().toLowerCase() + "spawn")) {
                     return true;
                 }
@@ -326,8 +332,8 @@ public boolean hasSpawn(final String string) {
     @Override
     public void initate(final Player player) {
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
-        if (!getLifeMap().containsKey(aPlayer.getName())) {
-            getLifeMap().put(aPlayer.getName(), arena.getArenaConfig()
+        if (!this.getLifeMap().containsKey(aPlayer.getName())) {
+            this.getLifeMap().put(aPlayer.getName(), this.arena.getArenaConfig()
                     .getInt(CFG.GOAL_CHECKPOINTS_LIVES));
         }
     }
@@ -339,51 +345,47 @@ public boolean isInternal() {
 
     @Override
     public void lateJoin(final Player player) {
-        initate(player);
+        this.initate(player);
     }
 
     @Override
     public void parseStart() {
-        getLifeMap().clear();
-        for (final ArenaPlayer player : arena.getFighters()) {
-            arena.getDebugger().i("adding player " + player.getName());
-            getLifeMap().put(player.getName(),
-                    arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES, 3));
+        this.getLifeMap().clear();
+        for (final ArenaPlayer player : this.arena.getFighters()) {
+            this.arena.getDebugger().i("adding player " + player.getName());
+            this.getLifeMap().put(player.getName(),
+                    this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_LIVES, 3));
         }
 
-        final CheckPointsMainRunnable cpMainRunner = new CheckPointsMainRunnable(arena, this);
-        final int tickInterval = arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_TICKINTERVAL);
-        cpMainRunner.rID = Bukkit.getScheduler().scheduleSyncRepeatingTask(
-                PVPArena.instance, cpMainRunner, tickInterval, tickInterval);
+        final CheckPointsMainRunnable cpMainRunner = new CheckPointsMainRunnable(this.arena, this);
+        final int tickInterval = this.arena.getArenaConfig().getInt(CFG.GOAL_CHECKPOINTS_TICKINTERVAL);
+        cpMainRunner.runTaskTimer(PVPArena.instance, tickInterval, tickInterval);
     }
 
-    private boolean reduceLivesCheckEndAndCommit(final Arena arena, final String player) {
+    private void reduceLivesCheckEndAndCommit(final Arena arena, final String player) {
 
         arena.getDebugger().i("reducing lives of player " + player);
-        if (getLifeMap().get(player) != null) {
-            final int iLives = getLifeMap().get(player) - 1;
+        if (this.getLifeMap().get(player) != null) {
+            final int iLives = this.getLifeMap().get(player) - 1;
             if (iLives > 0) {
-                getLifeMap().put(player, iLives);
+                this.getLifeMap().put(player, iLives);
             } else {
-                getLifeMap().remove(player);
-                commitWin(arena, player);
-                return true;
+                this.getLifeMap().remove(player);
+                this.commitWin(arena, player);
             }
         }
-        return false;
     }
 
     @Override
     public void reset(final boolean force) {
-        getLifeMap().clear();
+        this.getLifeMap().clear();
     }
 
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaTeam team : arena.getTeams()) {
-            double score = getLifeMap().containsKey(team.getName()) ? getLifeMap()
-                    .get(team.getName()) : 0;
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            double score = this.getLifeMap().getOrDefault(team.getName(), 0);
             if (scores.containsKey(team.getName())) {
                 scores.put(team.getName(), scores.get(team.getName()) + score);
             } else {
@@ -394,8 +396,7 @@ public Map timedEnd(final Map scores) {
         return scores;
     }
 
-    class CheckPointsMainRunnable implements Runnable {
-        public int rID = -1;
+    private class CheckPointsMainRunnable extends BukkitRunnable {
         private final Arena arena;
         //private final Debug debug = new Debug(39);
         private final GoalCheckPoints goal;
@@ -411,10 +412,10 @@ public CheckPointsMainRunnable(final Arena arena, final GoalCheckPoints goal) {
          */
         @Override
         public void run() {
-            if (!arena.isFightInProgress() || arena.realEndRunner != null) {
-                Bukkit.getScheduler().cancelTask(rID);
+            if (!this.arena.isFightInProgress() || this.arena.realEndRunner != null) {
+                this.cancel();
             }
-            goal.checkMove();
+            this.goal.checkMove();
         }
     }
 }
diff --git a/src/net/slipcor/pvparena/goals/GoalDomination.java b/src/net/slipcor/pvparena/goals/GoalDomination.java
index 9f366c30b..1778a586c 100644
--- a/src/net/slipcor/pvparena/goals/GoalDomination.java
+++ b/src/net/slipcor/pvparena/goals/GoalDomination.java
@@ -8,11 +8,9 @@
 import net.slipcor.pvparena.arena.ArenaTeam;
 import net.slipcor.pvparena.classes.*;
 import net.slipcor.pvparena.commands.PAA_Region;
+import net.slipcor.pvparena.core.*;
 import net.slipcor.pvparena.core.Config.CFG;
-import net.slipcor.pvparena.core.Debug;
-import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
@@ -25,6 +23,7 @@
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
 import org.bukkit.scheduler.BukkitTask;
 
 import java.util.*;
@@ -39,11 +38,14 @@
 
 public class GoalDomination extends ArenaGoal {
 
+    private static final int PRIORITY = 8;
+    private static final int INTERVAL = 200;
+
     private BukkitTask circleTask = null;
 
     public GoalDomination() {
         super("Domination");
-        debug = new Debug(99);
+        this.debug = new Debug(99);
     }
 
     private Map flagMap = new HashMap<>();
@@ -57,29 +59,27 @@ public String version() {
         return PVPArena.instance.getDescription().getVersion();
     }
 
-    private static final int PRIORITY = 8;
-
     @Override
     public boolean allowsJoinInBattle() {
-        return arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
+        return this.arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
     }
 
-    private void barStart(Location location, String title, ChatColor color, int range, long interval) {
-        if (!arena.getArenaConfig().getBoolean(CFG.GOAL_DOM_BOSSBAR)) {
+    private void barStart(Location location, String title, ChatColor color, int range) {
+        if (!this.arena.getArenaConfig().getBoolean(CFG.GOAL_DOM_BOSSBAR)) {
             return;
         }
-        if (getBarMap().containsKey(location)) {
-            PAClaimBar claimBar = getBarMap().get(location);
-            claimBar.restart(title, color, location, range, interval);
+        if (this.getBarMap().containsKey(location)) {
+            PAClaimBar claimBar = this.getBarMap().get(location);
+            claimBar.restart(title, color, location, range, INTERVAL);
         } else {
-            PAClaimBar claimBar = new PAClaimBar(arena, title, color, location, range, interval);
-            getBarMap().put(location, claimBar);
+            PAClaimBar claimBar = new PAClaimBar(this.arena, title, color, location, range, INTERVAL);
+            this.getBarMap().put(location, claimBar);
         }
     }
 
     private void barStop(Location location) {
-        if (getBarMap().containsKey(location)) {
-            getBarMap().get(location).stop();
+        if (this.getBarMap().containsKey(location)) {
+            this.getBarMap().get(location).stop();
         }
     }
 
@@ -108,12 +108,12 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        final int count = TeamManager.countActiveTeams(arena);
+        final int count = TeamManager.countActiveTeams(this.arena);
 
         if (count == 1) {
             res.setPriority(this, PRIORITY); // yep. only one team left. go!
         } else if (count == 0) {
-            arena.getDebugger().i("No teams playing!");
+            this.arena.getDebugger().i("No teams playing!");
         }
 
         return res;
@@ -122,7 +122,7 @@ public PACheck checkEnd(final PACheck res) {
     @Override
     public String checkForMissingSpawns(final Set list) {
 
-        final String team = checkForMissingTeamSpawn(list);
+        final String team = this.checkForMissingTeamSpawn(list);
         if (team != null) {
             return team;
         }
@@ -144,12 +144,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -157,12 +157,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -181,10 +181,11 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
      */
     private Set checkLocationPresentTeams(final Location loc, final int distance) {
         final Set result = new HashSet<>();
+        final Location flagCenter = Utils.getCenteredLocation(loc);
 
-        for (final ArenaPlayer p : arena.getFighters()) {
+        for (final ArenaPlayer p : this.arena.getFighters()) {
 
-            if (p.get().getLocation().distance(loc) > distance) {
+            if (p.get().getLocation().distance(flagCenter) > distance) {
                 continue;
             }
 
@@ -196,155 +197,151 @@ private Set checkLocationPresentTeams(final Location loc, final int dist
 
     void checkMove() {
 
-        /**
-         * possible Situations
-         *
-         * >>- flag is unclaimed and no one is there
-         * >>- flag is unclaimed and team a is there
-         * >>- flag is unclaimed and multiple teams are there
-         *
-         * >>- flag is being claimed by team a, no one is present
-         * >>- flag is being claimed by team a, team a is present
-         * >>- flag is being claimed by team a, multiple teams are present
-         * >>- flag is being claimed by team a, team b is present
-         *
-         * >>- flag is claimed by team a, no one is present
-         * >>- flag is claimed by team a, team a is present
-         * >>- flag is claimed by team a, multiple teams are present
-         * >>- flag is claimed by team a, team b is present
-         *
-         * >>- flag is claimed by team a and being unclaimed, no one is present
-         * >>- flag is claimed by team a and being unclaimed, team a is present
-         * >>- flag is claimed by team a and being unclaimed, multiple teams are present
-         * >>- flag is claimed by team a and being unclaimed, team b is present
-         *
+        /*
+          possible Situations
+
+          >>- flag is unclaimed and no one is there
+          >>- flag is unclaimed and team a is there
+          >>- flag is unclaimed and multiple teams are there
+
+          >>- flag is being claimed by team a, no one is present
+          >>- flag is being claimed by team a, team a is present
+          >>- flag is being claimed by team a, multiple teams are present
+          >>- flag is being claimed by team a, team b is present
+
+          >>- flag is claimed by team a, no one is present
+          >>- flag is claimed by team a, team a is present
+          >>- flag is claimed by team a, multiple teams are present
+          >>- flag is claimed by team a, team b is present
+
+          >>- flag is claimed by team a and being unclaimed, no one is present
+          >>- flag is claimed by team a and being unclaimed, team a is present
+          >>- flag is claimed by team a and being unclaimed, multiple teams are present
+          >>- flag is claimed by team a and being unclaimed, team b is present
+
          */
 
-        arena.getDebugger().i("------------------");
-        arena.getDebugger().i("   checkMove();");
-        arena.getDebugger().i("------------------");
+        this.arena.getDebugger().i("------------------");
+        this.arena.getDebugger().i("   checkMove();");
+        this.arena.getDebugger().i("------------------");
 
-        final int checkDistance = arena.getArenaConfig().getInt(
-                CFG.GOAL_DOM_CLAIMRANGE);
+        final int checkDistance = this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE);
 
-        for (final PABlockLocation paLoc : SpawnManager.getBlocksStartingWith(arena, "flag")) {
+        for (final PABlockLocation paLoc : SpawnManager.getBlocksStartingWith(this.arena, "flag")) {
             // arena.getDebugger().info("checking location: " + loc.toString());
 
             final Location loc = paLoc.toLocation();
 
-            final Set teams = checkLocationPresentTeams(paLoc.toLocation(),
-                    checkDistance);
+            final Set teams = this.checkLocationPresentTeams(loc, checkDistance);
 
-            arena.getDebugger().i("teams: " + StringParser.joinSet(teams, ", "));
+            this.arena.getDebugger().i("teams: " + StringParser.joinSet(teams, ", "));
 
             // teams now contains all teams near the flag
 
             if (teams.size() < 1) {
                 // arena.getDebugger().info("=> noone there!");
                 // no one there
-                if (getRunnerMap().containsKey(loc)) {
-                    arena.getDebugger().i("flag is being (un)claimed! Cancelling!");
+                if (this.getRunnerMap().containsKey(loc)) {
+                    this.arena.getDebugger().i("flag is being (un)claimed! Cancelling!");
                     // cancel unclaiming/claiming if noone's near
-                    Bukkit.getScheduler().cancelTask(getRunnerMap().get(loc).runID);
-                    getRunnerMap().remove(loc);
-                    barStop(loc);
+                    this.getRunnerMap().get(loc).cancel();
+                    this.getRunnerMap().remove(loc);
+                    this.barStop(loc);
                 }
-                if (getFlagMap().containsKey(loc)) {
-                    final String team = getFlagMap().get(loc);
+                if (this.getFlagMap().containsKey(loc)) {
+                    final String team = this.getFlagMap().get(loc);
 
-                    if (!getLifeMap().containsKey(team)) {
+                    if (!this.getLifeMap().containsKey(team)) {
                         continue;
                     }
 
                     // flag claimed! add score!
-                    maybeAddScoreAndBroadCast(team);
+                    this.maybeAddScoreAndBroadCast(team);
                 }
                 continue;
             }
 
             // there are actually teams at the flag
-            arena.getDebugger().i("=> at least one team is at the flag!");
+            this.arena.getDebugger().i("=> at least one team is at the flag!");
 
-            if (getFlagMap().containsKey(loc)) {
+            if (this.getFlagMap().containsKey(loc)) {
                 // flag is taken. by whom?
-                if (teams.contains(getFlagMap().get(loc))) {
+                if (teams.contains(this.getFlagMap().get(loc))) {
                     // owning team is there
-                    arena.getDebugger().i("  - owning team is there");
+                    this.arena.getDebugger().i("  - owning team is there");
                     if (teams.size() > 1) {
                         // another team is there
-                        arena.getDebugger().i("    - and another one");
-                        if (getRunnerMap().containsKey(loc)) {
+                        this.arena.getDebugger().i("    - and another one");
+                        if (this.getRunnerMap().containsKey(loc)) {
                             // it is being unclaimed
-                            arena.getDebugger().i("      - being unclaimed. continue!");
+                            this.arena.getDebugger().i("      - being unclaimed. continue!");
                         } else {
                             // unclaim
-                            arena.getDebugger().i("      - not being unclaimed. do it!");
-                            ArenaTeam team = arena.getTeam(getFlagMap().get(loc));
-                            arena.broadcast(Language.parse(arena, MSG.GOAL_DOMINATION_CONTESTING, team.getColoredName() + ChatColor.YELLOW));
+                            this.arena.getDebugger().i("      - not being unclaimed. do it!");
+                            ArenaTeam team = this.arena.getTeam(this.getFlagMap().get(loc));
+                            String contestingMsg = Language.parse(this.arena, MSG.GOAL_DOMINATION_CONTESTING, team.getColoredName() + ChatColor.YELLOW);
+                            this.arena.broadcast(contestingMsg);
                             final DominationRunnable domRunner = new DominationRunnable(
-                                    arena, false, loc,
-                                    getFlagMap().get(loc), this);
-                            domRunner.runID = Bukkit.getScheduler()
-                                    .scheduleSyncRepeatingTask(
-                                            PVPArena.instance, domRunner, 10 * 20L,
-                                            10 * 20L);
-                            getRunnerMap().put(loc, domRunner);
-                            barStart(loc, "unclaiming", ChatColor.WHITE, arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE), 200L);
+                                    this.arena, false, loc,
+                                    this.getFlagMap().get(loc), this);
+
+                            domRunner.runTaskTimer(PVPArena.instance, INTERVAL, INTERVAL);
+
+                            this.getRunnerMap().put(loc, domRunner);
+                            this.barStart(loc, contestingMsg, ChatColor.WHITE, checkDistance);
                         }
                     } else {
                         // just the owning team is there
-                        arena.getDebugger().i("    - noone else");
-                        if (getRunnerMap().containsKey(loc)) {
-                            arena.getDebugger().i("      - being unclaimed. cancel!");
+                        this.arena.getDebugger().i("    - noone else");
+                        if (this.getRunnerMap().containsKey(loc)) {
+                            this.arena.getDebugger().i("      - being unclaimed. cancel!");
                             // it is being unclaimed
                             // cancel task!
-                            Bukkit.getScheduler()
-                                    .cancelTask(getRunnerMap().get(loc).runID);
-                            getRunnerMap().remove(loc);
-                            barStop(loc);
+                            this.getRunnerMap().get(loc).cancel();
+                            this.getRunnerMap().remove(loc);
+                            this.barStop(loc);
                         } else {
 
-                            final String team = getFlagMap().get(loc);
+                            final String team = this.getFlagMap().get(loc);
 
-                            if (!getLifeMap().containsKey(team)) {
+                            if (!this.getLifeMap().containsKey(team)) {
                                 continue;
                             }
 
-                            maybeAddScoreAndBroadCast(team);
+                            this.maybeAddScoreAndBroadCast(team);
                         }
                     }
                     continue;
                 }
 
-                arena.getDebugger().i("  - owning team is not there!");
+                this.arena.getDebugger().i("  - owning team is not there!");
                 // owning team is NOT there ==> unclaim!
 
-                if (getRunnerMap().containsKey(loc)) {
-                    if (getRunnerMap().get(loc).take) {
-                        arena.getDebugger().i("    - runnable is trying to score, abort");
+                if (this.getRunnerMap().containsKey(loc)) {
+                    if (this.getRunnerMap().get(loc).isTaken()) {
+                        this.arena.getDebugger().i("    - runnable is trying to score, abort");
 
-                        Bukkit.getScheduler().cancelTask(getRunnerMap().get(loc).runID);
-                        getRunnerMap().remove(loc);
+                        this.getRunnerMap().get(loc).cancel();
+                        this.getRunnerMap().remove(loc);
                     } else {
-                        arena.getDebugger().i("    - being unclaimed. continue.");
+                        this.arena.getDebugger().i("    - being unclaimed. continue.");
                     }
                     continue;
                 }
-                arena.getDebugger().i("    - not yet being unclaimed, do it!");
+                this.arena.getDebugger().i("    - not yet being unclaimed, do it!");
                 // create an unclaim runnable
-                ArenaTeam team = arena.getTeam(getFlagMap().get(loc));
-                arena.broadcast(Language.parse(arena, MSG.GOAL_DOMINATION_UNCLAIMING, team.getColoredName() + ChatColor.YELLOW));
-                final DominationRunnable running = new DominationRunnable(arena,
-                        false, loc, getFlagMap().get(loc), this);
-                final long interval = 20L * 10;
-
-                running.runID = Bukkit.getScheduler().scheduleSyncRepeatingTask(
-                        PVPArena.instance, running, interval, interval);
-                getRunnerMap().put(loc, running);
-                barStart(loc, "unclaiming", ChatColor.WHITE, arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE), interval);
+                ArenaTeam team = this.arena.getTeam(this.getFlagMap().get(loc));
+                String unclaimingMsg = Language.parse(this.arena, MSG.GOAL_DOMINATION_UNCLAIMING, team.getColoredName() + ChatColor.YELLOW);
+                this.arena.broadcast(unclaimingMsg);
+                final DominationRunnable running = new DominationRunnable(this.arena,
+                        false, loc, this.getFlagMap().get(loc), this);
+
+                running.runTaskTimer(PVPArena.instance, INTERVAL, INTERVAL);
+                this.getRunnerMap().put(loc, running);
+                this.barStart(loc, unclaimingMsg, ChatColor.WHITE, checkDistance);
             } else {
                 // flag not taken
-                arena.getDebugger().i("- flag not taken");
+                this.arena.getDebugger().i("- flag not taken");
 
 				/*
                  * check if a runnable
@@ -357,46 +354,43 @@ void checkMove() {
 				 * 			yes => create runnable;
 				 * 			no => continue
 				 */
-                if (getRunnerMap().containsKey(loc)) {
-                    arena.getDebugger().i("  - being claimed");
+                if (this.getRunnerMap().containsKey(loc)) {
+                    this.arena.getDebugger().i("  - being claimed");
                     if (teams.size() < 2) {
-                        arena.getDebugger().i("  - only one team present");
-                        if (teams.contains(getRunnerMap().get(loc).team)) {
+                        this.arena.getDebugger().i("  - only one team present");
+                        if (teams.contains(this.getRunnerMap().get(loc).team)) {
                             // just THE team that is claiming => NEXT
-                            arena.getDebugger().i("  - claiming team present. next!");
+                            this.arena.getDebugger().i("  - claiming team present. next!");
                             continue;
                         }
                     }
-                    arena.getDebugger().i("  - more than one team or another team. cancel claim!");
+                    this.arena.getDebugger().i("  - more than one team or another team. cancel claim!");
                     // more than THE team that is claiming => cancel!
-                    Bukkit.getScheduler().cancelTask(getRunnerMap().get(loc).runID);
-                    getRunnerMap().remove(loc);
-                    barStop(loc);
+                    this.getRunnerMap().get(loc).cancel();
+                    this.getRunnerMap().remove(loc);
+                    this.barStop(loc);
                 } else {
-                    arena.getDebugger().i("  - not being claimed");
+                    this.arena.getDebugger().i("  - not being claimed");
                     // not being claimed
                     if (teams.size() < 2) {
-                        arena.getDebugger().i("  - just one team present");
+                        this.arena.getDebugger().i("  - just one team present");
                         for (final String sName : teams) {
-                            arena.getDebugger().i("TEAM " + sName + " IS CLAIMING "
+                            this.arena.getDebugger().i("TEAM " + sName + " IS CLAIMING "
                                     + loc);
-                            final ArenaTeam team = arena.getTeam(sName);
-                            arena.broadcast(Language.parse(arena,
-                                    MSG.GOAL_DOMINATION_CLAIMING,
-                                    team.getColoredName() + ChatColor.YELLOW));
+                            final ArenaTeam team = this.arena.getTeam(sName);
+                            String claimingMsg = Language.parse(this.arena, MSG.GOAL_DOMINATION_CLAIMING,
+                                    team.getColoredName() + ChatColor.YELLOW);
+                            this.arena.broadcast(claimingMsg);
 
                             final DominationRunnable running = new DominationRunnable(
-                                    arena, true, loc, sName, this);
-                            final long interval = 20L * 10;
-                            running.runID = Bukkit.getScheduler()
-                                    .scheduleSyncRepeatingTask(
-                                            PVPArena.instance, running,
-                                            interval, interval);
-                            getRunnerMap().put(loc, running);
-                            barStart(loc, "claiming...", team.getColor(), arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE), interval);
+                                    this.arena, true, loc, sName, this);
+
+                            running.runTaskTimer(PVPArena.instance, INTERVAL, INTERVAL);
+                            this.getRunnerMap().put(loc, running);
+                            this.barStart(loc, claimingMsg, team.getColor(), checkDistance);
                         }
                     } else {
-                        arena.getDebugger().i("  - more than one team present. continue!");
+                        this.arena.getDebugger().i("  - more than one team present. continue!");
                     }
                 }
             }
@@ -404,9 +398,9 @@ void checkMove() {
     }
 
     private void maybeAddScoreAndBroadCast(final String team) {
-        if (arena.getArenaConfig().getBoolean(CFG.GOAL_DOM_ONLYWHENMORE)) {
+        if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_DOM_ONLYWHENMORE)) {
             final Map claimed = new HashMap<>();
-            for (final String s : getFlagMap().values()) {
+            for (final String s : this.getFlagMap().values()) {
                 final int toAdd;
                 if (claimed.containsKey(s)) {
                     toAdd = claimed.get(s) + 1;
@@ -425,32 +419,31 @@ private void maybeAddScoreAndBroadCast(final String team) {
             }
         }
 
-        reduceLivesCheckEndAndCommit(arena, team);
+        this.reduceLivesCheckEndAndCommit(this.arena, team);
 
-        final int max = arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES);
-        if (!getLifeMap().containsKey(team)) {
+        final int max = this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES);
+        if (!this.getLifeMap().containsKey(team)) {
             return;
         }
 
-        final int lives = getLifeMap().get(team);
+        final int lives = this.getLifeMap().get(team);
 
-        if ((max - lives) % announceOffset != 0) {
+        if ((max - lives) % this.announceOffset != 0) {
             return;
         }
 
-        arena.broadcast(Language.parse(arena, MSG.GOAL_DOMINATION_SCORE,
-                arena.getTeam(team).getColoredName()
+        this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_DOMINATION_SCORE,
+                this.arena.getTeam(team).getColoredName()
                         + ChatColor.YELLOW, (max - lives) + "/" + max));
     }
 
     @Override
     public PACheck checkSetBlock(final PACheck res, final Player player, final Block block) {
 
-        if (res.getPriority() > PRIORITY
-                || !PAA_Region.activeSelections.containsKey(player.getName())) {
+        if (res.getPriority() > PRIORITY || !PAA_Region.activeSelections.containsKey(player.getName())) {
             return res;
         }
-        if (block == null || block.getType() != Material.WOOL) {
+        if (block == null || !ColorUtils.isColorableMaterial(block.getType())) {
             return res;
         }
         res.setPriority(this, PRIORITY); // success :)
@@ -507,7 +500,7 @@ private void commit(final Arena arena, final String sTeam) {
                             + ChatColor.YELLOW));
         }
 
-        getLifeMap().clear();
+        this.getLifeMap().clear();
         new EndRunnable(arena, arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
@@ -516,27 +509,27 @@ private void commit(final Arena arena, final String sTeam) {
     public void commitCommand(final CommandSender sender, final String[] args) {
         if (PAA_Region.activeSelections.containsKey(sender.getName())) {
             PAA_Region.activeSelections.remove(sender.getName());
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_SET, "flags"));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_SET, "flags"));
         } else {
 
-            PAA_Region.activeSelections.put(sender.getName(), arena);
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_TOSET, "flags"));
+            PAA_Region.activeSelections.put(sender.getName(), this.arena);
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_TOSET, "flags"));
         }
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[DOMINATION] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[DOMINATION] already ending");
             return;
         }
-        arena.getDebugger().i("[DOMINATION]");
+        this.arena.getDebugger().i("[DOMINATION]");
 
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
         ArenaTeam aTeam = null;
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() == Status.FIGHT) {
                     aTeam = team;
@@ -547,22 +540,22 @@ public void commitEnd(final boolean force) {
 
         if (aTeam != null && !force) {
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "END");
 
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "WINNER");
-            arena.broadcast(Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+            this.arena.broadcast(Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                     + aTeam.getName() + ChatColor.YELLOW));
         }
 
-        if (ArenaModuleManager.commitEnd(arena, aTeam)) {
+        if (ArenaModuleManager.commitEnd(this.arena, aTeam)) {
             return;
         }
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
+        new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
 
@@ -570,13 +563,11 @@ public void commitEnd(final boolean force) {
     public boolean commitSetFlag(final Player player, final Block block) {
 
         if (PVPArena.hasAdminPerms(player)
-                || PVPArena.hasCreatePerms(player, arena)
-                && player.getEquipment().getItemInMainHand() != null
-                && player.getEquipment().getItemInMainHand().getType().name().equals(arena
+                || PVPArena.hasCreatePerms(player, this.arena)
+                && player.getInventory().getItemInMainHand().getType().toString().equals(this.arena
                 .getArenaConfig().getString(CFG.GENERAL_WAND))) {
 
-            final Set flags = SpawnManager.getBlocksStartingWith(arena,
-                    "flag");
+            final Set flags = SpawnManager.getBlocksStartingWith(this.arena,"flag");
 
             if (flags.contains(new PABlockLocation(block.getLocation()))) {
                 return false;
@@ -584,10 +575,9 @@ public boolean commitSetFlag(final Player player, final Block block) {
 
             final String flagName = "flag" + flags.size();
 
-            SpawnManager.setBlock(arena,
-                    new PABlockLocation(block.getLocation()), flagName);
+            SpawnManager.setBlock(this.arena, new PABlockLocation(block.getLocation()), flagName);
 
-            arena.msg(player, Language.parse(arena, MSG.GOAL_FLAGS_SET, flagName));
+            this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_FLAGS_SET, flagName));
             return true;
         }
         return false;
@@ -595,24 +585,22 @@ public boolean commitSetFlag(final Player player, final Block block) {
 
     @Override
     public void displayInfo(final CommandSender sender) {
-        sender.sendMessage("needed points: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES));
-        sender.sendMessage("claim range: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE));
+        sender.sendMessage("needed points: " + this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES));
+        sender.sendMessage("claim range: " + this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_CLAIMRANGE));
     }
 
     private Map getFlagMap() {
-        if (flagMap == null) {
-            flagMap = new HashMap<>();
+        if (this.flagMap == null) {
+            this.flagMap = new HashMap<>();
         }
-        return flagMap;
+        return this.flagMap;
     }
 
     private Map getBarMap() {
-        if (flagBars == null) {
-            flagBars = new HashMap<>();
+        if (this.flagBars == null) {
+            this.flagBars = new HashMap<>();
         }
-        return flagBars;
+        return this.flagBars;
     }
 
     @Override
@@ -620,30 +608,29 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam()
-                            .getName()) ? getLifeMap().get(aPlayer
-                            .getArenaTeam().getName()) : 0));
+                    String.valueOf(this.getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
 
     private Map getRunnerMap() {
-        if (runnerMap == null) {
-            runnerMap = new HashMap<>();
+        if (this.runnerMap == null) {
+            this.runnerMap = new HashMap<>();
         }
-        return runnerMap;
+        return this.runnerMap;
     }
 
     @Override
     public boolean hasSpawn(final String string) {
-        for (final String teamName : arena.getTeamNames()) {
+        for (final String teamName : this.arena.getTeamNames()) {
             if (string.toLowerCase().startsWith(
                     teamName.toLowerCase() + "spawn")) {
                 return true;
             }
 
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(teamName.toLowerCase() +
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -658,13 +645,13 @@ public boolean hasSpawn(final String string) {
     public void initate(final Player player) {
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
         final ArenaTeam team = aPlayer.getArenaTeam();
-        if (!getLifeMap().containsKey(team.getName())) {
-            getLifeMap().put(aPlayer.getArenaTeam().getName(), arena.getArenaConfig()
+        if (!this.getLifeMap().containsKey(team.getName())) {
+            this.getLifeMap().put(aPlayer.getArenaTeam().getName(), this.arena.getArenaConfig()
                     .getInt(CFG.GOAL_DOM_LIVES));
 
-            final Set spawns = SpawnManager.getBlocksStartingWith(arena, "flag");
+            final Set spawns = SpawnManager.getBlocksStartingWith(this.arena, "flag");
             for (final PABlockLocation spawn : spawns) {
-                takeFlag(spawn);
+                this.takeFlag(spawn);
             }
         }
     }
@@ -676,66 +663,65 @@ public boolean isInternal() {
 
     @Override
     public void parseStart() {
-        getLifeMap().clear();
-        for (final ArenaTeam team : arena.getTeams()) {
+        this.getLifeMap().clear();
+        for (final ArenaTeam team : this.arena.getTeams()) {
             if (!team.getTeamMembers().isEmpty()) {
-                arena.getDebugger().i("adding team " + team.getName());
+                this.arena.getDebugger().i("adding team " + team.getName());
                 // team is active
-                getLifeMap().put(team.getName(),
-                        arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES, 3));
+                this.getLifeMap().put(team.getName(),
+                        this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_LIVES, 3));
             }
         }
-        final Set spawns = SpawnManager.getBlocksStartingWith(arena, "flag");
+        final Set spawns = SpawnManager.getBlocksStartingWith(this.arena, "flag");
         for (final PABlockLocation spawn : spawns) {
-            takeFlag(spawn);
+            this.takeFlag(spawn);
         }
 
-        final DominationMainRunnable domMainRunner = new DominationMainRunnable(arena, this);
-        final int tickInterval = arena.getArenaConfig().getInt(CFG.GOAL_DOM_TICKINTERVAL);
-        domMainRunner.rID = Bukkit.getScheduler().scheduleSyncRepeatingTask(
-                PVPArena.instance, domMainRunner, tickInterval, tickInterval);
+        final DominationMainRunnable domMainRunner = new DominationMainRunnable(this.arena, this);
+        final int tickInterval = this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_TICKINTERVAL);
+        domMainRunner.runTaskTimer(PVPArena.instance, tickInterval, tickInterval);
 
-        announceOffset = arena.getArenaConfig().getInt(CFG.GOAL_DOM_ANNOUNCEOFFSET);
+        this.announceOffset = this.arena.getArenaConfig().getInt(CFG.GOAL_DOM_ANNOUNCEOFFSET);
 
-        circleTask = Bukkit.getScheduler().runTaskTimer(PVPArena.instance, new CircleParticleRunnable(arena, CFG.GOAL_DOM_CLAIMRANGE), 1L, 1L);
+        if(this.arena.getArenaConfig().getBoolean(CFG.GOAL_DOM_PARTICLECIRCLE)) {
+            this.circleTask = Bukkit.getScheduler().runTaskTimer(PVPArena.instance, new CircleParticleRunnable(this.arena, CFG.GOAL_DOM_CLAIMRANGE, this.getFlagMap()), 1L, 1L);
+        }
     }
 
-    private boolean reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
+    private void reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
 
         arena.getDebugger().i("reducing lives of team " + team);
-        if (getLifeMap().get(team) != null) {
+        if (this.getLifeMap().get(team) != null) {
             final int score = arena.getArenaConfig().getInt(CFG.GOAL_DOM_TICKREWARD);
-            final int iLives = getLifeMap().get(team) - score;
+            final int iLives = this.getLifeMap().get(team) - score;
 
             final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "score:null:"+team+":"+score);
             Bukkit.getPluginManager().callEvent(gEvent);
 
             if (iLives > 0) {
-                getLifeMap().put(team, iLives);
+                this.getLifeMap().put(team, iLives);
             } else {
-                getLifeMap().remove(team);
-                commit(arena, team);
-                return true;
+                this.getLifeMap().remove(team);
+                this.commit(arena, team);
             }
         }
-        return false;
     }
 
     @Override
     public void reset(final boolean force) {
-        getBarMap().clear();
-        getLifeMap().clear();
-        getRunnerMap().clear();
-        getFlagMap().clear();
-        if (circleTask != null) {
-            circleTask.cancel();
-            circleTask = null;
+        this.getBarMap().clear();
+        this.getLifeMap().clear();
+        this.getRunnerMap().clear();
+        this.getFlagMap().clear();
+        if (this.circleTask != null) {
+            this.circleTask.cancel();
+            this.circleTask = null;
         }
     }
 
     @Override
     public void setDefaults(final YamlConfiguration config) {
-        if (arena.isFreeForAll()) {
+        if (this.arena.isFreeForAll()) {
             return;
         }
 
@@ -743,7 +729,7 @@ public void setDefaults(final YamlConfiguration config) {
             config.set("teams", null);
         }
         if (config.get("teams") == null) {
-            arena.getDebugger().i("no teams defined, adding custom red and blue!");
+            this.arena.getDebugger().i("no teams defined, adding custom red and blue!");
             config.addDefault("teams.red", ChatColor.RED.name());
             config.addDefault("teams.blue", ChatColor.BLUE.name());
         }
@@ -753,17 +739,16 @@ public void setDefaults(final YamlConfiguration config) {
      * take/reset an arena flag
      *
      * @param paBlockLocation the location to take/reset*/
-    void takeFlag(final PABlockLocation paBlockLocation) {
-        paBlockLocation.toLocation().getBlock()
-                .setData(StringParser.getColorDataFromENUM("WHITE"));
+    private void takeFlag(final PABlockLocation paBlockLocation) {
+        Block flagBlock = paBlockLocation.toLocation().getBlock();
+        ColorUtils.setNewFlagColor(flagBlock, ChatColor.WHITE);
     }
 
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaTeam team : arena.getTeams()) {
-            double score = getLifeMap().containsKey(team.getName()) ? getLifeMap()
-                    .get(team.getName()) : 0;
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            double score = this.getLifeMap().getOrDefault(team.getName(), 0);
             if (scores.containsKey(team.getName())) {
                 scores.put(team.getName(), scores.get(team.getName()) + score);
             } else {
@@ -774,13 +759,11 @@ public Map timedEnd(final Map scores) {
         return scores;
     }
 
-    class DominationRunnable implements Runnable {
-        public final boolean take;
-        public final Location loc;
-        public int runID = -1;
+    private static class DominationRunnable extends BukkitRunnable {
+        private final boolean taken;
+        private final Location loc;
         private final Arena arena;
         public final String team;
-        //private final Debug debug = new Debug(39);
         private final GoalDomination domination;
 
         /**
@@ -788,13 +771,13 @@ class DominationRunnable implements Runnable {
          *
          * @param arena the arena we are running in
          */
-        public DominationRunnable(final Arena arena, final boolean take, final Location loc2, final String teamName,
+        public DominationRunnable(final Arena arena, final boolean taken, final Location loc2, final String teamName,
                                   final GoalDomination goal) {
             this.arena = arena;
-            this.take = take;
-            team = teamName;
-            loc = loc2;
-            domination = goal;
+            this.taken = taken;
+            this.team = teamName;
+            this.loc = loc2;
+            this.domination = goal;
             arena.getDebugger().i("Domination constructor");
         }
 
@@ -803,63 +786,64 @@ public DominationRunnable(final Arena arena, final boolean take, final Location
          */
         @Override
         public void run() {
-            arena.getDebugger().i("DominationRunnable commiting");
-            arena.getDebugger().i("team " + team + ", take: " + take);
-            if (take) {
+            this.arena.getDebugger().i("DominationRunnable commiting");
+            this.arena.getDebugger().i("team " + this.team + ", take: " + this.taken);
+            if (this.taken) {
                 // claim a flag for the team
-                if (!domination.getFlagMap().containsKey(loc)) {
+                if (!this.domination.getFlagMap().containsKey(this.loc)) {
                     // flag unclaimed! claim!
-                    arena.getDebugger().i("clag unclaimed. claim!");
-                    domination.getFlagMap().put(loc, team);
+                    this.arena.getDebugger().i("clag unclaimed. claim!");
+                    this.domination.getFlagMap().put(this.loc, this.team);
                     // long interval = 20L * 5;
 
-                    arena.broadcast(Language.parse(arena,
-                            MSG.GOAL_DOMINATION_CLAIMED, arena.getTeam(team)
+                    this.arena.broadcast(Language.parse(this.arena,
+                            MSG.GOAL_DOMINATION_CLAIMED, this.arena.getTeam(this.team)
                                     .getColoredName() + ChatColor.YELLOW));
-                    takeFlag(arena, loc, team);
-                    domination.getFlagMap().put(loc, team);
+                    this.takeFlag(this.arena, this.loc, this.team);
+                    this.domination.getFlagMap().put(this.loc, this.team);
 
                     // claim done. end timer
-                    Bukkit.getScheduler().cancelTask(runID);
-                    domination.getRunnerMap().remove(loc);
+                    this.cancel();
+                    this.domination.getRunnerMap().remove(this.loc);
                 }
             } else {
                 // unclaim
-                arena.getDebugger().i("unclaimed");
-                takeFlag(arena, loc, "");
-                Bukkit.getScheduler().cancelTask(runID);
-                domination.getRunnerMap().remove(loc);
-                domination.getFlagMap().remove(loc);
+                this.arena.getDebugger().i("unclaimed");
+                this.takeFlag(this.arena, this.loc, "");
+                this.cancel();
+                this.domination.getRunnerMap().remove(this.loc);
+                this.domination.getFlagMap().remove(this.loc);
             }
         }
 
 
         private void takeFlag(final Arena arena, final Location lBlock, final String name) {
             ArenaTeam team = null;
+            Block flagBlock = lBlock.getBlock();
             for (final ArenaTeam t : arena.getTeams()) {
                 if (t.getName().equals(name)) {
                     team = t;
                 }
             }
             if (team == null) {
-                lBlock.getBlock().setData(
-                        StringParser.getColorDataFromENUM("WHITE"));
-                return;
+                ColorUtils.setNewFlagColor(flagBlock, ChatColor.WHITE);
+            } else {
+                ColorUtils.setNewFlagColor(flagBlock, team.getColor());
             }
-            lBlock.getBlock().setData(
-                    StringParser.getColorDataFromENUM(team.getColor().name()));
+        }
+
+        private boolean isTaken() {
+            return this.taken;
         }
     }
 
-    class DominationMainRunnable implements Runnable {
-        public int rID = -1;
+    private static class DominationMainRunnable extends BukkitRunnable {
         private final Arena arena;
-        //private final Debug debug = new Debug(39);
         private final GoalDomination domination;
 
         public DominationMainRunnable(final Arena arena, final GoalDomination goal) {
             this.arena = arena;
-            domination = goal;
+            this.domination = goal;
             arena.getDebugger().i("DominationMainRunnable constructor");
         }
 
@@ -868,10 +852,10 @@ public DominationMainRunnable(final Arena arena, final GoalDomination goal) {
          */
         @Override
         public void run() {
-            if (!arena.isFightInProgress() || arena.realEndRunner != null) {
-                Bukkit.getScheduler().cancelTask(rID);
+            if (!this.arena.isFightInProgress() || this.arena.realEndRunner != null) {
+                this.cancel();
             }
-            domination.checkMove();
+            this.domination.checkMove();
         }
     }
 }
diff --git a/src/net/slipcor/pvparena/goals/GoalFlags.java b/src/net/slipcor/pvparena/goals/GoalFlags.java
index 129f5ef97..ddb16dd35 100644
--- a/src/net/slipcor/pvparena/goals/GoalFlags.java
+++ b/src/net/slipcor/pvparena/goals/GoalFlags.java
@@ -10,22 +10,23 @@
 import net.slipcor.pvparena.classes.PACheck;
 import net.slipcor.pvparena.commands.CommandTree;
 import net.slipcor.pvparena.commands.PAA_Region;
+import net.slipcor.pvparena.core.*;
 import net.slipcor.pvparena.core.Config.CFG;
-import net.slipcor.pvparena.core.Debug;
-import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
 import net.slipcor.pvparena.managers.SpawnManager;
-import net.slipcor.pvparena.managers.StatisticsManager.type;
+import net.slipcor.pvparena.managers.StatisticsManager.Type;
 import net.slipcor.pvparena.managers.TeamManager;
 import net.slipcor.pvparena.runnables.EndRunnable;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.block.data.Directional;
+import org.bukkit.block.data.Rotatable;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Player;
@@ -41,6 +42,8 @@
 import org.bukkit.util.Vector;
 
 import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 
@@ -54,26 +57,26 @@
 
 public class GoalFlags extends ArenaGoal implements Listener {
 
-    public GoalFlags() {
-        super("Flags");
-        debug = new Debug(100);
-    }
-
+    private static final int PRIORITY = 6;
+    private static final String TOUCHDOWN = "touchdown";
     private Map flagMap;
     private Map headGearMap;
 
     private String flagName = "";
 
+    public GoalFlags() {
+        super("Flags");
+        this.debug = new Debug(100);
+    }
+
     @Override
     public String version() {
         return PVPArena.instance.getDescription().getVersion();
     }
 
-    private static final int PRIORITY = 6;
-
     @Override
     public boolean allowsJoinInBattle() {
-        return arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
+        return this.arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
     }
 
     @Override
@@ -82,13 +85,11 @@ public PACheck checkCommand(final PACheck res, final String string) {
             return res;
         }
 
-        if ("flagtype".equalsIgnoreCase(string)
-                || "flageffect".equalsIgnoreCase(string)
-                || "touchdown".equalsIgnoreCase(string)) {
+        if ("flagtype".equalsIgnoreCase(string) || "flageffect".equalsIgnoreCase(string) || TOUCHDOWN.equalsIgnoreCase(string)) {
             res.setPriority(this, PRIORITY);
         }
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             final String sTeam = team.getName();
             if (string.contains(sTeam + "flag")) {
                 res.setPriority(this, PRIORITY);
@@ -100,9 +101,9 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Arrays.asList("flagtype", "flageffect", "touchdown");
-        if (arena != null) {
-            for (final ArenaTeam team : arena.getTeams()) {
+        final List result = Stream.of("flagtype", "flageffect", TOUCHDOWN).collect(Collectors.toList());
+        if (this.arena != null) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 result.add(sTeam + "flag");
             }
@@ -124,12 +125,12 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        final int count = TeamManager.countActiveTeams(arena);
+        final int count = TeamManager.countActiveTeams(this.arena);
 
         if (count == 1) {
             res.setPriority(this, PRIORITY); // yep. only one team left. go!
         } else if (count == 0) {
-            arena.getDebugger().i("No teams playing!");
+            this.arena.getDebugger().i("No teams playing!");
         }
 
         return res;
@@ -137,12 +138,12 @@ public PACheck checkEnd(final PACheck res) {
 
     @Override
     public String checkForMissingSpawns(final Set list) {
-        final String team = checkForMissingTeamSpawn(list);
+        final String team = this.checkForMissingTeamSpawn(list);
         if (team != null) {
             return team;
         }
 
-        return checkForMissingTeamCustom(list, "flag");
+        return this.checkForMissingTeamCustom(list, "flag");
     }
 
     /**
@@ -158,113 +159,109 @@ public PACheck checkInteract(final PACheck res, final Player player, final Block
         if (block == null || res.getPriority() > PRIORITY) {
             return res;
         }
-        arena.getDebugger().i("checking interact", player);
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[CTF] already ending!!");
+        this.arena.getDebugger().i("checking interact", player);
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[CTF] already ending!!");
             return res;
         }
 
-        ItemStack flagType = StringParser.getItemStackFromString(arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGTYPE));
-        if (block.getType() != flagType.getType() || (flagType.getData().getData()>0 && flagType.getData().getData() != block.getData())) {
-            arena.getDebugger().i("block, but not flag", player);
+        Material flagType = this.arena.getArenaConfig().getMaterial(CFG.GOAL_FLAGS_FLAGTYPE);
+        if (!ColorUtils.isSubType(block.getType(), flagType)) {
+            this.arena.getDebugger().i("block, but not flag", player);
             return res;
         }
-        arena.getDebugger().i("flag click!", player);
+        this.arena.getDebugger().i("flag click!", player);
 
         Vector vLoc;
         Vector vFlag = null;
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
 
-        if (getFlagMap().containsValue(player.getName())) {
-            arena.getDebugger().i("player " + player.getName() + " has got a flag", player);
+        if (this.getFlagMap().containsValue(player.getName())) {
+            this.arena.getDebugger().i("player " + player.getName() + " has got a flag", player);
             vLoc = block.getLocation().toVector();
             final String sTeam = aPlayer.getArenaTeam().getName();
-            arena.getDebugger().i("block: " + vLoc, player);
-            if (!SpawnManager.getBlocksStartingWith(arena, sTeam + "flag").isEmpty()) {
+            this.arena.getDebugger().i("block: " + vLoc, player);
+            if (!SpawnManager.getBlocksStartingWith(this.arena, sTeam + "flag").isEmpty()) {
                 vFlag = SpawnManager
                         .getBlockNearest(
-                                SpawnManager.getBlocksStartingWith(arena, sTeam + "flag"),
+                                SpawnManager.getBlocksStartingWith(this.arena, sTeam + "flag"),
                                 new PABlockLocation(player.getLocation()))
                         .toLocation().toVector();
             } else {
-                arena.getDebugger().i(sTeam + "flag = null", player);
+                this.arena.getDebugger().i(sTeam + "flag = null", player);
             }
 
-            arena.getDebugger().i("player is in the team " + sTeam, player);
+            this.arena.getDebugger().i("player is in the team " + sTeam, player);
             if (vFlag != null && vLoc.distance(vFlag) < 2) {
 
-                arena.getDebugger().i("player is at his flag", player);
+                this.arena.getDebugger().i("player is at his flag", player);
 
-                if (getFlagMap().containsKey(sTeam)
-                        || getFlagMap().containsKey("touchdown")) {
-                    arena.getDebugger().i("the flag of the own team is taken!", player);
+                if (this.getFlagMap().containsKey(sTeam) || this.getFlagMap().containsKey(TOUCHDOWN)) {
+                    this.arena.getDebugger().i("the flag of the own team is taken!", player);
 
-                    if (arena.getArenaConfig().getBoolean(
+                    if (this.arena.getArenaConfig().getBoolean(
                             CFG.GOAL_FLAGS_MUSTBESAFE)
-                            && !getFlagMap().containsKey("touchdown")) {
-                        arena.getDebugger().i("cancelling", player);
+                            && !this.getFlagMap().containsKey(TOUCHDOWN)) {
+                        this.arena.getDebugger().i("cancelling", player);
 
-                        arena.msg(player,
-                                Language.parse(arena, MSG.GOAL_FLAGS_NOTSAFE));
+                        this.arena.msg(player,
+                                Language.parse(this.arena, MSG.GOAL_FLAGS_NOTSAFE));
                         return res;
                     }
                 }
 
-                String flagTeam = getHeldFlagTeam(player.getName());
+                String flagTeam = this.getHeldFlagTeam(player.getName());
 
-                arena.getDebugger().i("the flag belongs to team " + flagTeam, player);
+                this.arena.getDebugger().i("the flag belongs to team " + flagTeam, player);
 
                 try {
-                    if ("touchdown".equals(flagTeam)) {
-                        arena.broadcast(Language.parse(arena,
-                                MSG.GOAL_FLAGS_TOUCHHOME, arena.getTeam(sTeam)
+                    if (TOUCHDOWN.equals(flagTeam)) {
+                        this.arena.broadcast(Language.parse(this.arena,
+                                MSG.GOAL_FLAGS_TOUCHHOME, this.arena.getTeam(sTeam)
                                         .colorizePlayer(player)
                                         + ChatColor.YELLOW, String
-                                        .valueOf(getLifeMap().get(aPlayer
+                                        .valueOf(this.getLifeMap().get(aPlayer
                                                 .getArenaTeam().getName()) - 1)));
                     } else {
-                        arena.broadcast(Language.parse(arena,
-                                MSG.GOAL_FLAGS_BROUGHTHOME, arena
+                        this.arena.broadcast(Language.parse(this.arena,
+                                MSG.GOAL_FLAGS_BROUGHTHOME, this.arena
                                         .getTeam(sTeam).colorizePlayer(player)
                                         + ChatColor.YELLOW,
-                                arena.getTeam(flagTeam).getColoredName()
+                                this.arena.getTeam(flagTeam).getColoredName()
                                         + ChatColor.YELLOW, String
-                                        .valueOf(getLifeMap().get(flagTeam) - 1)));
+                                        .valueOf(this.getLifeMap().get(flagTeam) - 1)));
                     }
-                    getFlagMap().remove(flagTeam);
+                    this.getFlagMap().remove(flagTeam);
                 } catch (final Exception e) {
                     Bukkit.getLogger().severe(
                             "[PVP Arena] team unknown/no lives: " + flagTeam);
                     e.printStackTrace();
                 }
-                if ("touchdown".equals(flagTeam)) {
-                    takeFlag(ChatColor.BLACK.name(), false,
-                            SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+                if (TOUCHDOWN.equals(flagTeam)) {
+                    this.releaseFlag(ChatColor.BLACK, this.getTeamFlagLoc(TOUCHDOWN));
                 } else {
-                    takeFlag(arena.getTeam(flagTeam).getColor().name(), false,
-                            SpawnManager.getBlockByExactName(arena, flagTeam + "flag"));
+                    this.releaseFlag(this.arena.getTeam(flagTeam).getColor(), this.getTeamFlagLoc(flagTeam));
                 }
-                removeEffects(player);
-                if (arena.getArenaConfig().getBoolean(
+                this.removeEffects(player);
+                if (this.arena.getArenaConfig().getBoolean(
                         CFG.GOAL_FLAGS_WOOLFLAGHEAD)) {
-                    if (getHeadGearMap().get(player.getName()) == null) {
+                    if (this.getHeadGearMap().get(player.getName()) == null) {
                         player.getInventory().setHelmet(
                                 new ItemStack(Material.AIR, 1));
                     } else {
                         player.getInventory().setHelmet(
-                                getHeadGearMap().get(player.getName()).clone());
-                        getHeadGearMap().remove(player.getName());
+                                this.getHeadGearMap().get(player.getName()).clone());
+                        this.getHeadGearMap().remove(player.getName());
                     }
                 }
 
-                flagTeam = "touchdown".equals(flagTeam) ? flagTeam + ':' + aPlayer
+                flagTeam = TOUCHDOWN.equals(flagTeam) ? flagTeam + ':' + aPlayer
                         .getArenaTeam().getName() : flagTeam;
 
-                reduceLivesCheckEndAndCommit(arena, flagTeam); // TODO move to
+                this.reduceLivesCheckEndAndCommit(this.arena, flagTeam); // TODO move to
                 // "commit" ?
 
-                final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "trigger:" + aPlayer.getName());
+                final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "trigger:" + aPlayer.getName());
                 Bukkit.getPluginManager().callEvent(gEvent);
             }
         } else {
@@ -272,76 +269,72 @@ public PACheck checkInteract(final PACheck res, final Player player, final Block
             if (pTeam == null) {
                 return res;
             }
-            final Set setTeam = new HashSet<>();
 
-            for (final ArenaTeam team : arena.getTeams()) {
-                setTeam.add(team);
-            }
-            setTeam.add(new ArenaTeam("touchdown", "BLACK"));
+            final Set setTeam = new HashSet<>(this.arena.getTeams());
+
+            setTeam.add(new ArenaTeam(TOUCHDOWN, "BLACK"));
             for (final ArenaTeam team : setTeam) {
                 final String aTeam = team.getName();
 
                 if (aTeam.equals(pTeam.getName())) {
-                    arena.getDebugger().i("equals!OUT! ", player);
+                    this.arena.getDebugger().i("equals!OUT! ", player);
                     continue;
                 }
-                if (team.getTeamMembers().size() < 1
-                        && !"touchdown".equals(team.getName())) {
-                    arena.getDebugger().i("size!OUT! ", player);
+
+                if (team.getTeamMembers().size() < 1 && !TOUCHDOWN.equals(team.getName())) {
+                    this.arena.getDebugger().i("size!OUT! ", player);
                     continue; // dont check for inactive teams
                 }
-                if (getFlagMap() != null && getFlagMap().containsKey(aTeam)) {
-                    arena.getDebugger().i("taken!OUT! ", player);
+
+                if (this.getFlagMap() != null && this.getFlagMap().containsKey(aTeam)) {
+                    this.arena.getDebugger().i("taken!OUT! ", player);
                     continue; // already taken
                 }
-                arena.getDebugger().i("checking for flag of team " + aTeam, player);
+
+                this.arena.getDebugger().i("checking for flag of team " + aTeam, player);
                 vLoc = block.getLocation().toVector();
-                arena.getDebugger().i("block: " + vLoc, player);
-                if (!SpawnManager.getBlocksStartingWith(arena, aTeam + "flag").isEmpty()) {
+                this.arena.getDebugger().i("block: " + vLoc, player);
+
+                if (!SpawnManager.getBlocksStartingWith(this.arena, aTeam + "flag").isEmpty()) {
                     vFlag = SpawnManager
                             .getBlockNearest(
-                                    SpawnManager.getBlocksStartingWith(arena, aTeam
+                                    SpawnManager.getBlocksStartingWith(this.arena, aTeam
                                             + "flag"),
                                     new PABlockLocation(player.getLocation()))
                             .toLocation().toVector();
                 }
+
                 if (vFlag != null && vLoc.distance(vFlag) < 2) {
-                    arena.getDebugger().i("flag found!", player);
-                    arena.getDebugger().i("vFlag: " + vFlag, player);
+                    this.arena.getDebugger().i("flag found!", player);
+                    this.arena.getDebugger().i("vFlag: " + vFlag, player);
 
-                    if ("touchdown".equals(team.getName())) {
+                    if (TOUCHDOWN.equals(team.getName())) {
 
-                        arena.broadcast(Language.parse(arena,
+                        this.arena.broadcast(Language.parse(this.arena,
                                 MSG.GOAL_FLAGS_GRABBEDTOUCH,
                                 pTeam.colorizePlayer(player) + ChatColor.YELLOW));
                     } else {
 
-                        arena.broadcast(Language
-                                .parse(arena, MSG.GOAL_FLAGS_GRABBED,
+                        this.arena.broadcast(Language
+                                .parse(this.arena, MSG.GOAL_FLAGS_GRABBED,
                                         pTeam.colorizePlayer(player)
                                                 + ChatColor.YELLOW,
                                         team.getColoredName()
                                                 + ChatColor.YELLOW));
                     }
                     try {
-                        getHeadGearMap().put(player.getName(), player.getInventory()
-                                .getHelmet().clone());
-                    } catch (final Exception e) {
+                        this.getHeadGearMap().put(player.getName(), player.getInventory().getHelmet().clone());
+                    } catch (final Exception ignored) {
                     }
-                    final ItemStack itemStack = block.getState().getData().toItemStack()
-                            .clone();
-                    itemStack.setAmount(1);
-                    if (arena.getArenaConfig().getBoolean(
-                            CFG.GOAL_FLAGS_WOOLFLAGHEAD)) {
-                        itemStack.setDurability(getFlagOverrideTeamShort(arena, aTeam));
+
+                    if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)) {
+                        final ItemStack itemStack = new ItemStack(this.getFlagOverrideTeamMaterial(this.arena, aTeam));
+                        player.getInventory().setHelmet(itemStack);
                     }
-                    player.getInventory().setHelmet(itemStack);
-                    applyEffects(player);
+                    this.applyEffects(player);
 
-                    takeFlag(team.getColor().name(), true,
-                            new PABlockLocation(block.getLocation()));
-                    getFlagMap().put(aTeam, player.getName()); // TODO move to
-                    // "commit" ?
+                    this.takeFlag(new PABlockLocation(vFlag.toLocation(block.getWorld())));
+                    this.getFlagMap().put(aTeam, player.getName());
 
                     return res;
                 }
@@ -352,7 +345,7 @@ public PACheck checkInteract(final PACheck res, final Player player, final Block
     }
 
     private void applyEffects(final Player player) {
-        final String value = arena.getArenaConfig().getString(
+        final String value = this.arena.getArenaConfig().getString(
                 CFG.GOAL_FLAGS_FLAGEFFECT);
 
         if ("none".equalsIgnoreCase(value)) {
@@ -366,7 +359,7 @@ private void applyEffects(final Player player) {
         if (split.length > 1) {
             try {
                 amp = Integer.parseInt(split[1]);
-            } catch (final Exception e) {
+            } catch (final Exception ignored) {
             }
         }
 
@@ -396,12 +389,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -409,12 +402,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -426,19 +419,16 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
     @Override
     public PACheck checkSetBlock(final PACheck res, final Player player, final Block block) {
 
-        if (res.getPriority() > PRIORITY
-                || !PAA_Region.activeSelections.containsKey(player.getName())) {
+        if (res.getPriority() > PRIORITY || !PAA_Region.activeSelections.containsKey(player.getName())) {
             return res;
         }
 
-        ItemStack flagType = StringParser.getItemStackFromString(arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGTYPE));
-        if (block == null || block.getType() != flagType.getType() || (flagType.getData().getData()>0 && flagType.getData().getData() != block.getData())) {
+        Material flagType = this.arena.getArenaConfig().getMaterial(CFG.GOAL_FLAGS_FLAGTYPE);
+        if (block == null || !ColorUtils.isSubType(block.getType(), flagType)) {
             return res;
         }
 
-        if (!PVPArena.hasAdminPerms(player)
-                && !PVPArena.hasCreatePerms(player, arena)) {
+        if (!PVPArena.hasAdminPerms(player) && !PVPArena.hasCreatePerms(player, this.arena)) {
             return res;
         }
         res.setPriority(this, PRIORITY); // success :)
@@ -462,7 +452,7 @@ private void commit(final Arena arena, final String sTeam, final boolean win) {
             }
             for (final ArenaPlayer ap : team.getTeamMembers()) {
 
-                ap.addStatistic(arena.getName(), type.LOSSES, 1);
+                ap.addStatistic(arena.getName(), Type.LOSSES, 1);
                 /*
 				arena.tpPlayerToCoordName(ap.get(), "spectator");
 				ap.setTelePass(false);*/
@@ -494,7 +484,7 @@ private void commit(final Arena arena, final String sTeam, final boolean win) {
                             + ChatColor.YELLOW));
         }
 
-        getLifeMap().clear();
+        this.getLifeMap().clear();
         new EndRunnable(arena, arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
@@ -503,9 +493,9 @@ private void commit(final Arena arena, final String sTeam, final boolean win) {
     public void commitCommand(final CommandSender sender, final String[] args) {
         if ("flagtype".equalsIgnoreCase(args[0])) {
             if (args.length < 2) {
-                arena.msg(
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
+                        Language.parse(this.arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
                                 String.valueOf(args.length), "2"));
                 return;
             }
@@ -513,35 +503,35 @@ public void commitCommand(final CommandSender sender, final String[] args) {
             final Material mat = Material.getMaterial(args[1].toUpperCase());
 
             if (mat == null) {
-                arena.msg(sender,
-                        Language.parse(arena, MSG.ERROR_MAT_NOT_FOUND, args[1]));
+                this.arena.msg(sender,
+                        Language.parse(this.arena, MSG.ERROR_MAT_NOT_FOUND, args[1]));
                 return;
             }
 
-            arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGTYPE, mat.name());
+            this.arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGTYPE, mat.name());
 
-            arena.getArenaConfig().save();
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_TYPESET,
+            this.arena.getArenaConfig().save();
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_TYPESET,
                     CFG.GOAL_FLAGS_FLAGTYPE.toString()));
 
         } else if ("flageffect".equalsIgnoreCase(args[0])) {
 
             // /pa [arena] flageffect SLOW 2
             if (args.length < 2) {
-                arena.msg(
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
+                        Language.parse(this.arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
                                 String.valueOf(args.length), "2"));
                 return;
             }
 
             if ("none".equalsIgnoreCase(args[1])) {
-                arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, args[1]);
+                this.arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, args[1]);
 
-                arena.getArenaConfig().save();
-                arena.msg(
+                this.arena.getArenaConfig().save();
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.SET_DONE,
+                        Language.parse(this.arena, MSG.SET_DONE,
                                 CFG.GOAL_FLAGS_FLAGEFFECT.getNode(), args[1]));
                 return;
             }
@@ -559,7 +549,7 @@ public void commitCommand(final CommandSender sender, final String[] args) {
             }
 
             if (pet == null) {
-                arena.msg(sender, Language.parse(arena,
+                this.arena.msg(sender, Language.parse(this.arena,
                         MSG.ERROR_POTIONEFFECTTYPE_NOTFOUND, args[1]));
                 return;
             }
@@ -570,52 +560,52 @@ public void commitCommand(final CommandSender sender, final String[] args) {
                 try {
                     amp = Integer.parseInt(args[2]);
                 } catch (final Exception e) {
-                    arena.msg(sender,
-                            Language.parse(arena, MSG.ERROR_NOT_NUMERIC, args[2]));
+                    this.arena.msg(sender,
+                            Language.parse(this.arena, MSG.ERROR_NOT_NUMERIC, args[2]));
                     return;
                 }
             }
             final String value = args[1] + 'x' + amp;
-            arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, value);
+            this.arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, value);
 
-            arena.getArenaConfig().save();
-            arena.msg(
+            this.arena.getArenaConfig().save();
+            this.arena.msg(
                     sender,
-                    Language.parse(arena, MSG.SET_DONE,
+                    Language.parse(this.arena, MSG.SET_DONE,
                             CFG.GOAL_FLAGS_FLAGEFFECT.getNode(), value));
 
         } else if (args[0].contains("flag")) {
-            for (final ArenaTeam team : arena.getTeams()) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 if (args[0].contains(sTeam + "flag")) {
-                    flagName = args[0];
-                    PAA_Region.activeSelections.put(sender.getName(), arena);
+                    this.flagName = args[0];
+                    PAA_Region.activeSelections.put(sender.getName(), this.arena);
 
-                    arena.msg(sender,
-                            Language.parse(arena, MSG.GOAL_FLAGS_TOSET, flagName));
+                    this.arena.msg(sender,
+                            Language.parse(this.arena, MSG.GOAL_FLAGS_TOSET, this.flagName));
                 }
             }
-        } else if ("touchdown".equalsIgnoreCase(args[0])) {
-            flagName = args[0] + "flag";
-            PAA_Region.activeSelections.put(sender.getName(), arena);
+        } else if (TOUCHDOWN.equalsIgnoreCase(args[0])) {
+            this.flagName = args[0] + "flag";
+            PAA_Region.activeSelections.put(sender.getName(), this.arena);
 
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_TOSET, flagName));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_TOSET, this.flagName));
         }
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[FLAGS] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[FLAGS] already ending");
             return;
         }
-        arena.getDebugger().i("[FLAGS]");
+        this.arena.getDebugger().i("[FLAGS]");
 
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
         ArenaTeam aTeam = null;
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() == Status.FIGHT) {
                     aTeam = team;
@@ -626,40 +616,42 @@ public void commitEnd(final boolean force) {
 
         if (aTeam != null && !force) {
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "END");
 
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "WINNER");
-            arena.broadcast(Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+            this.arena.broadcast(Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                     + aTeam.getName() + ChatColor.YELLOW));
         }
 
-        if (ArenaModuleManager.commitEnd(arena, aTeam)) {
+        if (ArenaModuleManager.commitEnd(this.arena, aTeam)) {
             return;
         }
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
+        new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public boolean commitSetFlag(final Player player, final Block block) {
 
-        arena.getDebugger().i("trying to set a flag", player);
+        this.arena.getDebugger().i("trying to set a flag", player);
 
         // command : /pa redflag1
         // location: red1flag:
 
-        SpawnManager.setBlock(arena, new PABlockLocation(block.getLocation()),
-                flagName);
-
-        arena.msg(player, Language.parse(arena, MSG.GOAL_FLAGS_SET, flagName));
+        if(this.flagName == null || this.flagName.isEmpty()) {
+            this.arena.msg(player, Language.parse(this.arena, MSG.ERROR_ERROR, "Flag you are trying to set has no name."));
+        } else {
+            SpawnManager.setBlock(this.arena, new PABlockLocation(block.getLocation()), this.flagName);
+            this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_FLAGS_SET, this.flagName));
+        }
 
         PAA_Region.activeSelections.remove(player.getName());
-        flagName = "";
+        this.flagName = "";
 
         return true;
     }
@@ -676,84 +668,77 @@ public void configParse(final YamlConfiguration config) {
 
     @Override
     public void disconnect(final ArenaPlayer aPlayer) {
-        if (getFlagMap() == null) {
+        if (this.getFlagMap() == null) {
             return;
         }
-        final String sTeam = getHeldFlagTeam(aPlayer.getName());
-        final ArenaTeam flagTeam = arena.getTeam(sTeam);
+        final String sTeam = this.getHeldFlagTeam(aPlayer.getName());
+        final ArenaTeam flagTeam = this.arena.getTeam(sTeam);
 
         if (flagTeam == null) {
             if (sTeam == null) {
                 return;
             }
-            arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
                     .getArenaTeam().getColorCodeString()
                     + aPlayer.getName()
                     + ChatColor.YELLOW));
 
-            getFlagMap().remove("touchdown");
-            if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+            this.getFlagMap().remove(TOUCHDOWN);
+            if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
                 if (aPlayer.get() != null) {
                     aPlayer.get().getInventory()
-                            .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                            .setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
                 }
-                getHeadGearMap().remove(aPlayer.getName());
+                this.getHeadGearMap().remove(aPlayer.getName());
             }
 
-            takeFlag(ChatColor.BLACK.name(), false,
-                    SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+            this.releaseFlag(ChatColor.BLACK, this.getTeamFlagLoc(TOUCHDOWN));
 
             return;
         }
-        arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
+        this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
                 .getArenaTeam().getColorCodeString()
                 + aPlayer.getName()
                 + ChatColor.YELLOW, flagTeam.getName() + ChatColor.YELLOW));
-        getFlagMap().remove(flagTeam.getName());
-        if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+        this.getFlagMap().remove(flagTeam.getName());
+        if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
             if (aPlayer.get() != null) {
                 aPlayer.get().getInventory()
-                        .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                        .setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
             }
-            getHeadGearMap().remove(aPlayer.getName());
+            this.getHeadGearMap().remove(aPlayer.getName());
         }
 
-        takeFlag(flagTeam.getColor().name(), false,
-                SpawnManager.getBlockByExactName(arena, flagTeam.getName() + "flag"));
+        this.releaseFlag(flagTeam.getColor(), this.getTeamFlagLoc(flagTeam.getName()));
     }
 
     @Override
     public void displayInfo(final CommandSender sender) {
-        sender.sendMessage("flageffect: " +
-                arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGEFFECT));
-        sender.sendMessage("flagtype: " +
-                arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGTYPE));
-        sender.sendMessage("lives: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_FLAGS_LIVES));
-        sender.sendMessage(StringParser.colorVar("mustbesafe",
-                arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_MUSTBESAFE)) +
-                " | " + StringParser.colorVar("flaghead",
-                arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)));
+        Config cfg = this.arena.getArenaConfig();
+        sender.sendMessage("flageffect: " + cfg.getString(CFG.GOAL_FLAGS_FLAGEFFECT));
+        sender.sendMessage("flagtype: " + cfg.getString(CFG.GOAL_FLAGS_FLAGTYPE));
+        sender.sendMessage("lives: " + cfg.getInt(CFG.GOAL_FLAGS_LIVES));
+        sender.sendMessage(StringParser.colorVar("mustbesafe", cfg.getBoolean(CFG.GOAL_FLAGS_MUSTBESAFE))
+                + " | " + StringParser.colorVar("flaghead", cfg.getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD))
+                + " | " + StringParser.colorVar("alterOnCatch", cfg.getBoolean(CFG.GOAL_FLAGS_ALTERONCATCH)));
     }
 
     private Map getFlagMap() {
-        if (flagMap == null) {
-            flagMap = new HashMap<>();
+        if (this.flagMap == null) {
+            this.flagMap = new HashMap<>();
         }
-        return flagMap;
+        return this.flagMap;
     }
 
-    private short getFlagOverrideTeamShort(final Arena arena, final String team) {
+    private Material getFlagOverrideTeamMaterial(final Arena arena, final String team) {
         if (arena.getArenaConfig().getUnsafe("flagColors." + team) == null) {
-            if ("touchdown".equals(team)) {
-                return StringParser
-                        .getColorDataFromENUM(ChatColor.BLACK.name());
+            if (TOUCHDOWN.equals(team)) {
+                return ColorUtils.getWoolMaterialFromChatColor(ChatColor.BLACK);
             }
-            return StringParser.getColorDataFromENUM(arena.getTeam(team)
-                    .getColor().name());
+            return ColorUtils.getWoolMaterialFromChatColor(arena.getTeam(team).getColor());
         }
-        return StringParser.getColorDataFromENUM((String) arena
-                .getArenaConfig().getUnsafe("flagColors." + team));
+        return ColorUtils.getWoolMaterialFromDyeColor(
+                (String) arena.getArenaConfig().getUnsafe("flagColors." + team));
     }
 
     @Override
@@ -761,18 +746,17 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam()
-                            .getName()) ? getLifeMap().get(aPlayer
-                            .getArenaTeam().getName()) : 0));
+                    String.valueOf(this.getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
 
     private Map getHeadGearMap() {
-        if (headGearMap == null) {
-            headGearMap = new HashMap<>();
+        if (this.headGearMap == null) {
+            this.headGearMap = new HashMap<>();
         }
-        return headGearMap;
+        return this.headGearMap;
     }
 
     /**
@@ -782,15 +766,15 @@ private Map getHeadGearMap() {
      * @return a team name
      */
     private String getHeldFlagTeam(final String player) {
-        if (getFlagMap().size() < 1) {
+        if (this.getFlagMap().size() < 1) {
             return null;
         }
 
-        arena.getDebugger().i("getting held FLAG of player " + player, player);
-        for (final String sTeam : getFlagMap().keySet()) {
-            arena.getDebugger().i("team " + sTeam + " is in " + getFlagMap().get(sTeam)
+        this.arena.getDebugger().i("getting held FLAG of player " + player, player);
+        for (final String sTeam : this.getFlagMap().keySet()) {
+            this.arena.getDebugger().i("team " + sTeam + " is in " + this.getFlagMap().get(sTeam)
                     + "s hands", player);
-            if (player.equals(getFlagMap().get(sTeam))) {
+            if (player.equals(this.getFlagMap().get(sTeam))) {
                 return sTeam;
             }
         }
@@ -799,14 +783,14 @@ private String getHeldFlagTeam(final String player) {
 
     @Override
     public boolean hasSpawn(final String string) {
-        for (final String teamName : arena.getTeamNames()) {
+        for (final String teamName : this.arena.getTeamNames()) {
             if (string.toLowerCase().startsWith(
                     teamName.toLowerCase() + "spawn")) {
                 return true;
             }
 
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(teamName.toLowerCase() +
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -821,14 +805,12 @@ public boolean hasSpawn(final String string) {
     public void initate(final Player player) {
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
         final ArenaTeam team = aPlayer.getArenaTeam();
-        if (!getLifeMap().containsKey(team.getName())) {
-            getLifeMap().put(aPlayer.getArenaTeam().getName(), arena.getArenaConfig()
+        if (!this.getLifeMap().containsKey(team.getName())) {
+            this.getLifeMap().put(aPlayer.getArenaTeam().getName(), this.arena.getArenaConfig()
                     .getInt(CFG.GOAL_FLAGS_LIVES));
 
-            takeFlag(team.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, team.getName() + "flag"));
-            takeFlag(ChatColor.BLACK.name(), false,
-                    SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+            this.releaseFlag(team.getColor(), this.getTeamFlagLoc(team.getName()));
+            this.releaseFlag(ChatColor.BLACK, this.getTeamFlagLoc(TOUCHDOWN));
         }
     }
 
@@ -841,99 +823,90 @@ public boolean isInternal() {
     public void parsePlayerDeath(final Player player,
                                  final EntityDamageEvent lastDamageCause) {
 
-        if (getFlagMap() == null) {
-            arena.getDebugger().i("no flags set!!", player);
+        if (this.getFlagMap() == null) {
+            this.arena.getDebugger().i("no flags set!!", player);
             return;
         }
-        final String sTeam = getHeldFlagTeam(player.getName());
-        final ArenaTeam flagTeam = arena.getTeam(sTeam);
+        final String sTeam = this.getHeldFlagTeam(player.getName());
+        final ArenaTeam flagTeam = this.arena.getTeam(sTeam);
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
 
         if (flagTeam == null) {
             if (sTeam == null) {
                 return;
             }
-            arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
                     .getArenaTeam().getColorCodeString()
                     + aPlayer.getName()
                     + ChatColor.YELLOW));
 
-            getFlagMap().remove("touchdown");
-            if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+            this.getFlagMap().remove(TOUCHDOWN);
+            if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
                 if (aPlayer.get() != null) {
                     aPlayer.get().getInventory()
-                            .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                            .setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
                 }
-                getHeadGearMap().remove(aPlayer.getName());
+                this.getHeadGearMap().remove(aPlayer.getName());
             }
 
-            takeFlag(ChatColor.BLACK.name(), false,
-                    SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+            this.releaseFlag(ChatColor.BLACK, this.getTeamFlagLoc(TOUCHDOWN));
             return;
         }
-        arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
+        this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
                         .getArenaTeam().colorizePlayer(player) + ChatColor.YELLOW,
                 flagTeam.getColoredName() + ChatColor.YELLOW));
-        getFlagMap().remove(flagTeam.getName());
-        if (getHeadGearMap() != null
-                && getHeadGearMap().get(player.getName()) != null) {
-            player.getInventory().setHelmet(
-                    getHeadGearMap().get(player.getName()).clone());
-            getHeadGearMap().remove(player.getName());
+        this.getFlagMap().remove(flagTeam.getName());
+        if (this.getHeadGearMap() != null && this.getHeadGearMap().get(player.getName()) != null) {
+            player.getInventory().setHelmet(this.getHeadGearMap().get(player.getName()).clone());
+            this.getHeadGearMap().remove(player.getName());
         }
 
-        takeFlag(flagTeam.getColor().name(), false,
-                SpawnManager.getBlockByExactName(arena, flagTeam.getName() + "flag"));
+        this.releaseFlag(flagTeam.getColor(), this.getTeamFlagLoc(flagTeam.getName()));
     }
 
     @Override
     public void parseStart() {
-        getLifeMap().clear();
-        for (final ArenaTeam team : arena.getTeams()) {
+        this.getLifeMap().clear();
+        for (final ArenaTeam team : this.arena.getTeams()) {
             if (!team.getTeamMembers().isEmpty()) {
-                arena.getDebugger().i("adding team " + team.getName());
+                this.arena.getDebugger().i("adding team " + team.getName());
                 // team is active
-                getLifeMap().put(team.getName(),
-                        arena.getArenaConfig().getInt(CFG.GOAL_FLAGS_LIVES, 3));
+                this.getLifeMap().put(team.getName(),
+                        this.arena.getArenaConfig().getInt(CFG.GOAL_FLAGS_LIVES, 3));
             }
-            takeFlag(team.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, team.getName() + "flag"));
+            this.releaseFlag(team.getColor(), this.getTeamFlagLoc(team.getName()));
         }
-        takeFlag(ChatColor.BLACK.name(), false,
-                SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+        this.releaseFlag(ChatColor.BLACK, this.getTeamFlagLoc(TOUCHDOWN));
     }
 
-    private boolean reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
+    private void reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
 
         arena.getDebugger().i("reducing lives of team " + team);
 
-        if (getLifeMap().get(team) == null) {
+        if (this.getLifeMap().get(team) == null) {
             if (team.contains(":")) {
                 final String realTeam = team.split(":")[1];
-                final int pos = getLifeMap().get(realTeam) - 1;
+                final int pos = this.getLifeMap().get(realTeam) - 1;
                 if (pos > 0) {
-                    getLifeMap().put(realTeam, pos);
+                    this.getLifeMap().put(realTeam, pos);
                 } else {
-                    getLifeMap().remove(realTeam);
-                    commit(arena, realTeam, true);
-                    return true;
+                    this.getLifeMap().remove(realTeam);
+                    this.commit(arena, realTeam, true);
                 }
             }
         } else {
-            final int pos = getLifeMap().get(team) - 1;
+            final int pos = this.getLifeMap().get(team) - 1;
             if (pos > 0) {
-                getLifeMap().put(team, pos);
+                this.getLifeMap().put(team, pos);
             } else {
-                getLifeMap().remove(team);
-                commit(arena, team, false);
-                return true;
+                this.getLifeMap().remove(team);
+                this.commit(arena, team, false);
             }
         }
-        return false;
     }
 
     private void removeEffects(final Player player) {
-        final String value = arena.getArenaConfig().getString(
+        final String value = this.arena.getArenaConfig().getString(
                 CFG.GOAL_FLAGS_FLAGEFFECT);
 
         if ("none".equalsIgnoreCase(value)) {
@@ -955,8 +928,7 @@ private void removeEffects(final Player player) {
         }
 
         if (pet == null) {
-            PVPArena.instance.getLogger().warning(
-                    "Invalid Potion Effect Definition: " + value);
+            PVPArena.instance.getLogger().warning("Invalid Potion Effect Definition: " + value);
             return;
         }
 
@@ -966,14 +938,14 @@ private void removeEffects(final Player player) {
 
     @Override
     public void reset(final boolean force) {
-        getFlagMap().clear();
-        getHeadGearMap().clear();
-        getLifeMap().clear();
+        this.getFlagMap().clear();
+        this.getHeadGearMap().clear();
+        this.getLifeMap().clear();
     }
 
     @Override
     public void setDefaults(final YamlConfiguration config) {
-        if (arena.isFreeForAll()) {
+        if (this.arena.isFreeForAll()) {
             return;
         }
 
@@ -981,53 +953,80 @@ public void setDefaults(final YamlConfiguration config) {
             config.set("teams", null);
         }
         if (config.get("teams") == null) {
-            arena.getDebugger().i("no teams defined, adding custom red and blue!");
+            this.arena.getDebugger().i("no teams defined, adding custom red and blue!");
             config.addDefault("teams.red", ChatColor.RED.name());
             config.addDefault("teams.blue", ChatColor.BLUE.name());
         }
-        if (arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)
-                && config.get("flagColors") == null) {
-            arena.getDebugger().i("no flagheads defined, adding white and black!");
-            config.addDefault("flagColors.red", "WHITE");
-            config.addDefault("flagColors.blue", "BLACK");
+        if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD) && config.get("flagColors") == null) {
+            this.arena.getDebugger().i("no flagheads defined, adding white and black!");
+            config.addDefault("flagColors.red", ChatColor.WHITE.name());
+            config.addDefault("flagColors.blue", ChatColor.BLACK.name());
         }
     }
 
     /**
-     * take/reset an arena flag
+     * take an arena flag
      *
-     * @param flagColor       the teamcolor to reset
-     * @param take            true if take, else reset
      * @param paBlockLocation the location to take/reset
      */
-    void takeFlag(final String flagColor, final boolean take, final PABlockLocation paBlockLocation) {
+    private void takeFlag(final PABlockLocation paBlockLocation) {
         if (paBlockLocation == null) {
             return;
         }
-        if (!"WOOL".equals(arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGTYPE))) {
-            paBlockLocation.toLocation()
-                    .getBlock()
-                    .setType(
-                            take ? Material.BEDROCK : Material.valueOf(arena
-                                    .getArenaConfig().getString(
-                                            CFG.GOAL_FLAGS_FLAGTYPE)));
+
+        if(this.arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_ALTERONCATCH)) {
+            Block flagBlock = paBlockLocation.toLocation().getBlock();
+
+            if (ColorUtils.isColorableMaterial(flagBlock.getType())) {
+                ColorUtils.setNewFlagColor(flagBlock, ChatColor.WHITE);
+            } else {
+                flagBlock.setType(Material.BEDROCK);
+            }
+        }
+    }
+
+    /**
+     * reset an arena flag
+     *
+     * @param flagColor       the teamcolor to reset
+     * @param paBlockLocation the location to take/reset
+     */
+    private void releaseFlag(final ChatColor flagColor, final PABlockLocation paBlockLocation) {
+        if (paBlockLocation == null) {
             return;
         }
-        if (take) {
-            paBlockLocation.toLocation().getBlock()
-                    .setData(StringParser.getColorDataFromENUM("WHITE"));
-        } else {
-            paBlockLocation.toLocation().getBlock()
-                    .setData(StringParser.getColorDataFromENUM(flagColor));
+
+        if(this.arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_ALTERONCATCH)) {
+            Block flagBlock = paBlockLocation.toLocation().getBlock();
+
+            if (ColorUtils.isColorableMaterial(flagBlock.getType())) {
+                ColorUtils.setNewFlagColor(flagBlock, flagColor);
+            } else {
+                flagBlock.setType(this.arena.getArenaConfig().getMaterial(CFG.GOAL_FLAGS_FLAGTYPE));
+            }
         }
     }
 
+    private void setNewBlockData(Block block, Material newMaterial) {
+        final BlockData originalBlockData = block.getBlockData().clone();
+        BlockData newData = Bukkit.getServer().createBlockData(newMaterial);
+
+        if(originalBlockData instanceof Directional) {
+            ((Directional) newData).setFacing(((Directional) originalBlockData).getFacing());
+        }
+
+        if(originalBlockData instanceof Rotatable) {
+            ((Rotatable) newData).setRotation(((Rotatable) originalBlockData).getRotation());
+        }
+
+        block.setBlockData(newData);
+    }
+
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaTeam team : arena.getTeams()) {
-            double score = getLifeMap().containsKey(team.getName()) ? getLifeMap()
-                    .get(team.getName()) : 0;
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            double score = this.getLifeMap().getOrDefault(team.getName(), 0);
             if (scores.containsKey(team.getName())) {
                 scores.put(team.getName(), scores.get(team.getName()) + score);
             } else {
@@ -1040,9 +1039,9 @@ public Map timedEnd(final Map scores) {
 
     @Override
     public void unload(final Player player) {
-        disconnect(ArenaPlayer.parsePlayer(player.getName()));
-        if (allowsJoinInBattle()) {
-            arena.hasNotPlayed(ArenaPlayer.parsePlayer(player.getName()));
+        this.disconnect(ArenaPlayer.parsePlayer(player.getName()));
+        if (this.allowsJoinInBattle()) {
+            this.arena.hasNotPlayed(ArenaPlayer.parsePlayer(player.getName()));
         }
     }
 
@@ -1056,8 +1055,7 @@ public void onInventoryClick(final InventoryClickEvent event) {
             return;
         }
 
-        if (event.isCancelled()
-                || getHeldFlagTeam(player.getName()) == null) {
+        if (event.isCancelled() || this.getHeldFlagTeam(player.getName()) == null) {
             return;
         }
 
@@ -1070,4 +1068,8 @@ public void onInventoryClick(final InventoryClickEvent event) {
             event.setCancelled(true);
         }
     }
+
+    private PABlockLocation getTeamFlagLoc(String teamName) {
+        return SpawnManager.getBlockByExactName(this.arena, teamName + "flag");
+    }
 }
diff --git a/src/net/slipcor/pvparena/goals/GoalFood.java b/src/net/slipcor/pvparena/goals/GoalFood.java
index 53874ef0b..42fa66c15 100644
--- a/src/net/slipcor/pvparena/goals/GoalFood.java
+++ b/src/net/slipcor/pvparena/goals/GoalFood.java
@@ -71,11 +71,13 @@ public String version() {
     private static final Map cookmap = new HashMap<>();
 
     static {
-        cookmap.put(Material.RAW_BEEF, Material.COOKED_BEEF);
-        cookmap.put(Material.RAW_CHICKEN, Material.COOKED_CHICKEN);
-        cookmap.put(Material.RAW_FISH, Material.COOKED_FISH);
-        cookmap.put(Material.POTATO_ITEM, Material.BAKED_POTATO);
-        cookmap.put(Material.PORK, Material.GRILLED_PORK);
+        cookmap.put(Material.BEEF, Material.COOKED_BEEF);
+        cookmap.put(Material.CHICKEN, Material.COOKED_CHICKEN);
+        cookmap.put(Material.COD, Material.COOKED_COD);
+        cookmap.put(Material.MUTTON, Material.COOKED_MUTTON);
+        cookmap.put(Material.PORKCHOP, Material.COOKED_PORKCHOP);
+        cookmap.put(Material.POTATO, Material.BAKED_POTATO);
+        cookmap.put(Material.SALMON, Material.COOKED_SALMON);
     }
 
     @Override
@@ -101,7 +103,7 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Arrays.asList(new String[0]);
+        final List result = new ArrayList<>();
         if (arena != null) {
             for (final ArenaTeam team : arena.getTeams()) {
                 final String sTeam = team.getName();
@@ -275,17 +277,8 @@ public void commitEnd(final boolean force) {
     public void commitPlayerDeath(final Player respawnPlayer, final boolean doesRespawn,
                                   final String error, final PlayerDeathEvent event) {
 
-        final ArenaTeam respawnTeam = ArenaPlayer
-                .parsePlayer(respawnPlayer.getName()).getArenaTeam();
-
-        if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-            arena.broadcast(Language.parse(arena,
-                    MSG.FIGHT_KILLED_BY,
-                    respawnTeam.colorizePlayer(respawnPlayer)
-                            + ChatColor.YELLOW, arena.parseDeathCause(
-                            respawnPlayer, event.getEntity()
-                                    .getLastDamageCause().getCause(), event
-                                    .getEntity().getKiller())));
+        if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+            this.broadcastSimpleDeathMessage(respawnPlayer, event);
         }
 
         final List returned;
@@ -295,12 +288,10 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
             returned = InventoryManager.drop(respawnPlayer);
             event.getDrops().clear();
         } else {
-            returned = new ArrayList<>();
-            returned.addAll(event.getDrops());
+            returned = new ArrayList<>(event.getDrops());
         }
 
-        PACheck.handleRespawn(arena,
-                ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
+        PACheck.handleRespawn(this.arena, ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
 
     }
 
diff --git a/src/net/slipcor/pvparena/goals/GoalInfect.java b/src/net/slipcor/pvparena/goals/GoalInfect.java
index 96eecf835..30df95a23 100644
--- a/src/net/slipcor/pvparena/goals/GoalInfect.java
+++ b/src/net/slipcor/pvparena/goals/GoalInfect.java
@@ -30,11 +30,11 @@
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.event.block.BlockPlaceEvent;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityPickupItemEvent;
 import org.bukkit.event.entity.PlayerDeathEvent;
 import org.bukkit.event.inventory.CraftItemEvent;
 import org.bukkit.event.inventory.InventoryClickEvent;
 import org.bukkit.event.player.PlayerDropItemEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 import org.bukkit.inventory.ItemStack;
 
 import java.util.*;
@@ -52,7 +52,7 @@
 public class GoalInfect extends ArenaGoal {
     public GoalInfect() {
         super("Infect");
-        debug = new Debug(108);
+        this.debug = new Debug(108);
     }
 // BREAK, PLACE, TNT, TNTBREAK, DROP, INVENTORY, PICKUP, CRAFT;
     private EndRunnable endRunner;
@@ -70,10 +70,10 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        final int count = getLifeMap().size();
+        final int count = this.getLifeMap().size();
 
         if (count <= 1
-                || anyTeamEmpty()) {
+                || this.anyTeamEmpty()) {
             res.setPriority(this, PRIORITY); // yep. only one player left. go!
         }
         if (count == 0) {
@@ -84,17 +84,18 @@ public PACheck checkEnd(final PACheck res) {
     }
 
     private boolean anyTeamEmpty() {
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             boolean bbreak = false;
             for (final ArenaPlayer player : team.getTeamMembers()) {
                 if (player.getStatus() == Status.FIGHT) {
                     bbreak = true;
+                    break;
                 }
             }
             if (bbreak) {
                 continue;
             }
-            arena.getDebugger().i("team empty: " + team.getName());
+            this.arena.getDebugger().i("team empty: " + team.getName());
             return true;
         }
         return false;
@@ -102,7 +103,7 @@ private boolean anyTeamEmpty() {
 
     @Override
     public String checkForMissingSpawns(final Set list) {
-        if (!arena.isFreeForAll()) {
+        if (!this.arena.isFreeForAll()) {
             return null; // teams are handled somewhere else
         }
 
@@ -139,7 +140,7 @@ public PACheck checkCommand(final PACheck res, final String string) {
     @Override
     public PACheck checkBreak(PACheck result, Arena arena, BlockBreakEvent event) {
         ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getPlayer().getName());
-        if (arena.equals(ap.getArena())) {
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.BREAK
@@ -163,13 +164,13 @@ public PACheck checkBreak(PACheck result, Arena arena, BlockBreakEvent event) {
     @Override
     public PACheck checkCraft(PACheck result, Arena arena, CraftItemEvent event) {
         ArenaPlayer ap = ArenaPlayer.parsePlayer(((Player) event.getInventory().getHolder()).getName());
-        if (arena.equals(ap.getArena())) {
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.CRAFT
                 )) {
                     event.setCancelled(true);
-                    arena.msg((Player) event.getWhoClicked(), Language.parse(arena, MSG.PLAYER_PREVENTED_CRAFT));
+                    arena.msg(event.getWhoClicked(), Language.parse(arena, MSG.PLAYER_PREVENTED_CRAFT));
                     result.setError(this, "CRAFT not allowed");
                 }
             }
@@ -180,7 +181,7 @@ public PACheck checkCraft(PACheck result, Arena arena, CraftItemEvent event) {
     @Override
     public PACheck checkDrop(PACheck result, Arena arena, PlayerDropItemEvent event) {
         ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getPlayer().getName());
-        if (arena.equals(ap.getArena())) {
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.DROP
@@ -196,15 +197,15 @@ public PACheck checkDrop(PACheck result, Arena arena, PlayerDropItemEvent event)
 
     @Override
     public PACheck checkInventory(PACheck result, Arena arena, InventoryClickEvent event) {
-        ArenaPlayer ap = ArenaPlayer.parsePlayer(((Player) event.getWhoClicked()).getName());
-        if (arena.equals(ap.getArena())) {
+        ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getWhoClicked().getName());
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.INVENTORY
                 )) {
                     event.setCancelled(true);
                     event.getWhoClicked().closeInventory();
-                    arena.msg((Player) event.getWhoClicked(), Language.parse(arena, MSG.PLAYER_PREVENTED_INVENTORY));
+                    arena.msg(event.getWhoClicked(), Language.parse(arena, MSG.PLAYER_PREVENTED_INVENTORY));
                     result.setError(this, "INVENTORY not allowed");
                 }
             }
@@ -213,9 +214,9 @@ public PACheck checkInventory(PACheck result, Arena arena, InventoryClickEvent e
     }
 
     @Override
-    public PACheck checkPickup(PACheck result, Arena arena, PlayerPickupItemEvent event) {
-        ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getPlayer().getName());
-        if (arena.equals(ap.getArena())) {
+    public PACheck checkPickup(PACheck result, Arena arena, EntityPickupItemEvent event) {
+        ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getEntity().getName());
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.PICKUP
@@ -231,7 +232,7 @@ public PACheck checkPickup(PACheck result, Arena arena, PlayerPickupItemEvent ev
     @Override
     public PACheck checkPlace(PACheck result, Arena arena, BlockPlaceEvent event) {
         ArenaPlayer ap = ArenaPlayer.parsePlayer(event.getPlayer().getName());
-        if (arena.equals(ap.getArena())) {
+        if (arena.equals(ap.getArena()) && ap.getStatus() == Status.FIGHT) {
             if ("infected".equals(ap.getArenaTeam().getName())) {
                 if (ArenaPlayer.PlayerPrevention.has(
                         arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS), ArenaPlayer.PlayerPrevention.PLACE
@@ -258,12 +259,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -271,12 +272,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -290,11 +291,11 @@ public PACheck checkPlayerDeath(final PACheck res, final Player player) {
         if (res.getPriority() <= PRIORITY) {
             res.setPriority(this, PRIORITY);
 
-            if (!getLifeMap().containsKey(player.getName())) {
+            if (!this.getLifeMap().containsKey(player.getName())) {
                 return res;
             }
-            final int iLives = getLifeMap().get(player.getName());
-            arena.getDebugger().i("lives before death: " + iLives, player);
+            final int iLives = this.getLifeMap().get(player.getName());
+            this.arena.getDebugger().i("lives before death: " + iLives, player);
             if (iLives <= 1 && "infected".equals(ArenaPlayer.parsePlayer(player.getName()).getArenaTeam().getName())) {
                 res.setError(this, "0");
             }
@@ -314,7 +315,7 @@ public PACheck checkStart(final PACheck res) {
     @Override
     public void commitCommand(final CommandSender sender, final String[] args) {
 
-        int value = arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS);
+        int value = this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_PPROTECTS);
 
         if ("getprotect".equalsIgnoreCase(args[0])) {
             List values = new ArrayList<>();
@@ -327,14 +328,14 @@ public void commitCommand(final CommandSender sender, final String[] args) {
                 values.add((ArenaPlayer.PlayerPrevention.has(value, pp) ?
                         ChatColor.GREEN.toString() : ChatColor.RED.toString()) + pp.name());
             }
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_INFECTED_IPROTECT, StringParser.joinList(values, (ChatColor.WHITE + ", "))));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_INFECTED_IPROTECT, StringParser.joinList(values, (ChatColor.WHITE + ", "))));
 
         } else if ("setprotect".equalsIgnoreCase(args[0])) {
             // setprotect [value] {true|false}
             if (args.length < 2) {
-                arena.msg(
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
+                        Language.parse(this.arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
                                 String.valueOf(args.length), "2|3"));
                 return;
             }
@@ -343,9 +344,9 @@ public void commitCommand(final CommandSender sender, final String[] args) {
                 final ArenaPlayer.PlayerPrevention pp = ArenaPlayer.PlayerPrevention.valueOf(args[1].toUpperCase());
                 final boolean has = ArenaPlayer.PlayerPrevention.has(value, pp);
 
-                arena.getDebugger().i("plain value: " + value);
-                arena.getDebugger().i("checked: " + pp.name());
-                arena.getDebugger().i("has: " + String.valueOf(has));
+                this.arena.getDebugger().i("plain value: " + value);
+                this.arena.getDebugger().i("checked: " + pp.name());
+                this.arena.getDebugger().i("has: " + has);
 
                 boolean future = !has;
 
@@ -359,18 +360,18 @@ public void commitCommand(final CommandSender sender, final String[] args) {
 
                 if (future) {
                     value = value | (int) Math.pow(2, pp.ordinal());
-                    arena.msg(
+                    this.arena.msg(
                             sender,
-                            Language.parse(arena, MSG.GOAL_INFECTED_IPROTECT_SET,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_IPROTECT_SET,
                                     pp.name(), ChatColor.GREEN + "true") + ChatColor.YELLOW);
                 } else {
                     value = value ^ (int) Math.pow(2, pp.ordinal());
-                    arena.msg(
+                    this.arena.msg(
                             sender,
-                            Language.parse(arena, MSG.GOAL_INFECTED_IPROTECT_SET,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_IPROTECT_SET,
                                     pp.name(), ChatColor.RED + "false") + ChatColor.YELLOW);
                 }
-                arena.getArenaConfig().set(CFG.GOAL_INFECTED_PPROTECTS, value);
+                this.arena.getArenaConfig().set(CFG.GOAL_INFECTED_PPROTECTS, value);
             } catch (final Exception e) {
                 List values = new ArrayList<>();
 
@@ -378,218 +379,199 @@ public void commitCommand(final CommandSender sender, final String[] args) {
                 for (ArenaPlayer.PlayerPrevention pp : ArenaPlayer.PlayerPrevention.values()) {
                     values.add(pp.name());
                 }
-                arena.msg(sender,
-                        Language.parse(arena, MSG.ERROR_ARGUMENT, args[1], StringParser.joinList(values, ", ")));
+                this.arena.msg(sender,
+                        Language.parse(this.arena, MSG.ERROR_ARGUMENT, args[1], StringParser.joinList(values, ", ")));
                 return;
             }
-            arena.getArenaConfig().save();
+            this.arena.getArenaConfig().save();
 
         }
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (endRunner != null) {
+        if (this.endRunner != null) {
             return;
         }
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[INFECT] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[INFECT] already ending");
             return;
         }
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() != Status.FIGHT) {
                     continue;
                 }
                 if ("infected".equals(ap.getArenaTeam().getName())) {
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.GOAL_INFECTED_WON), "END");
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_WON), "END");
 
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.GOAL_INFECTED_WON), "WINNER");
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_WON), "WINNER");
 
-                    arena.broadcast(Language.parse(arena, MSG.GOAL_INFECTED_WON));
+                    this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_INFECTED_WON));
                     break;
                 } else {
 
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.GOAL_INFECTED_LOST), "END");
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_LOST), "END");
                     // String tank = tanks.get(arena);
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.GOAL_INFECTED_LOST), "LOSER");
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.GOAL_INFECTED_LOST), "LOSER");
 
-                    arena.broadcast(Language.parse(arena, MSG.GOAL_INFECTED_LOST));
+                    this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_INFECTED_LOST));
                     break;
                 }
             }
 
-            if (ArenaModuleManager.commitEnd(arena, team)) {
+            if (ArenaModuleManager.commitEnd(this.arena, team)) {
                 return;
             }
         }
 
-        endRunner = new EndRunnable(arena, arena.getArenaConfig().getInt(
+        this.endRunner = new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                                   final String error, final PlayerDeathEvent event) {
-        if (!getLifeMap().containsKey(player.getName())) {
+        if (!this.getLifeMap().containsKey(player.getName())) {
             return;
         }
-        int iLives = getLifeMap().get(player.getName());
-        arena.getDebugger().i("lives before death: " + iLives, player);
-        if (iLives <= 1 || "infected".equals(ArenaPlayer.parsePlayer(player.getName()).getArenaTeam().getName())) {
-            if (iLives <= 1 && "infected".equals(ArenaPlayer.parsePlayer(player.getName()).getArenaTeam().getName())) {
+        int iLives = this.getLifeMap().get(player.getName());
+        this.arena.getDebugger().i("lives before death: " + iLives, player);
+        ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
+        if (iLives <= 1 || "infected".equals(aPlayer.getArenaTeam().getName())) {
+            if (iLives <= 1 && "infected".equals(aPlayer.getArenaTeam().getName())) {
 
-                final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "infected", "playerDeath:" + player.getName());
+                final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "infected", "playerDeath:" + player.getName());
                 Bukkit.getPluginManager().callEvent(gEvent);
-                ArenaPlayer.parsePlayer(player.getName()).setStatus(Status.LOST);
+                aPlayer.setStatus(Status.LOST);
                 // kill, remove!
-                getLifeMap().remove(player.getName());
-                if (arena.getArenaConfig().getBoolean(CFG.PLAYER_PREVENTDEATH)) {
-                    arena.getDebugger().i("faking player death", player);
-                    PlayerListener.finallyKillPlayer(arena, player, event);
+                this.getLifeMap().remove(player.getName());
+                if (this.arena.getArenaConfig().getBoolean(CFG.PLAYER_PREVENTDEATH)) {
+                    this.arena.getDebugger().i("faking player death", player);
+                    PlayerListener.finallyKillPlayer(this.arena, player, event);
                 }
                 return;
             }
             if (iLives <= 1) {
-                PAGoalEvent gEvent = new PAGoalEvent(arena, this, "playerDeath:" + player.getName());
+                PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "playerDeath:" + player.getName());
                 Bukkit.getPluginManager().callEvent(gEvent);
                 // dying player -> infected
-                getLifeMap().put(player.getName(), arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
-                arena.msg(player, Language.parse(arena, MSG.GOAL_INFECTED_YOU));
-                arena.broadcast(Language.parse(arena, MSG.GOAL_INFECTED_PLAYER, player.getName()));
-
-                ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
+                this.getLifeMap().put(player.getName(), this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
+                this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_INFECTED_YOU));
+                this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_INFECTED_PLAYER, player.getName()));
 
                 final ArenaTeam oldTeam = aPlayer.getArenaTeam();
-                final ArenaTeam respawnTeam = arena.getTeam("infected");
+                final ArenaTeam respawnTeam = this.arena.getTeam("infected");
 
-                PATeamChangeEvent tcEvent = new PATeamChangeEvent(arena, player, oldTeam, respawnTeam);
+                PATeamChangeEvent tcEvent = new PATeamChangeEvent(this.arena, player, oldTeam, respawnTeam);
                 Bukkit.getPluginManager().callEvent(tcEvent);
-                arena.updateScoreboardTeam(player, oldTeam, respawnTeam);
+                this.arena.updateScoreboardTeam(player, oldTeam, respawnTeam);
 
                 oldTeam.remove(aPlayer);
 
                 respawnTeam.add(aPlayer);
 
-                final ArenaClass infectedClass = arena.getClass("%infected%");
+                final ArenaClass infectedClass = this.arena.getClass("%infected%");
                 if (infectedClass != null) {
                     aPlayer.setArenaClass(infectedClass);
                 }
 
-                if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                            arena.parseDeathCause(player, event.getEntity()
-                                            .getLastDamageCause().getCause(),
-                                    player.getKiller()), String.valueOf(iLives)));
+                if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                    this.broadcastSimpleDeathMessage(player, event);
                 }
 
                 final List returned;
 
-                if (arena.getArenaConfig().getBoolean(
+                if (this.arena.getArenaConfig().getBoolean(
                         CFG.PLAYER_DROPSINVENTORY)) {
                     returned = InventoryManager.drop(player);
                     event.getDrops().clear();
                 } else {
-                    returned = new ArrayList<>();
-                    returned.addAll(event.getDrops());
+                    returned = new ArrayList<>(event.getDrops());
                 }
 
-                PACheck.handleRespawn(arena,
-                        ArenaPlayer.parsePlayer(player.getName()), returned);
+                PACheck.handleRespawn(this.arena,
+                        aPlayer, returned);
 
-                if (anyTeamEmpty()) {
-                    PACheck.handleEnd(arena, false);
+                if (this.anyTeamEmpty()) {
+                    PACheck.handleEnd(this.arena, false);
                 }
                 return;
             }
             // dying infected player, has lives remaining
-            PAGoalEvent gEvent = new PAGoalEvent(arena, this, "infected", "doesRespawn", "playerDeath:" + player.getName());
+            PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "infected", "doesRespawn", "playerDeath:" + player.getName());
             Bukkit.getPluginManager().callEvent(gEvent);
             iLives--;
-            getLifeMap().put(player.getName(), iLives);
+            this.getLifeMap().put(player.getName(), iLives);
 
-            final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
+            final ArenaTeam respawnTeam = aPlayer
                     .getArenaTeam();
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY_REMAINING,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, event.getEntity()
-                                        .getLastDamageCause().getCause(),
-                                player.getKiller()), String.valueOf(iLives)));
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING, player, event, iLives);
             }
 
             final List returned;
 
-            if (arena.getArenaConfig().getBoolean(
+            if (this.arena.getArenaConfig().getBoolean(
                     CFG.PLAYER_DROPSINVENTORY)) {
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
-            PACheck.handleRespawn(arena,
-                    ArenaPlayer.parsePlayer(player.getName()), returned);
+            PACheck.handleRespawn(this.arena,
+                    aPlayer, returned);
 
 
             // player died => commit death!
-            PACheck.handleEnd(arena, false);
+            PACheck.handleEnd(this.arena, false);
         } else {
             iLives--;
-            getLifeMap().put(player.getName(), iLives);
+            this.getLifeMap().put(player.getName(), iLives);
 
-            final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
+            final ArenaTeam respawnTeam = aPlayer
                     .getArenaTeam();
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY_REMAINING,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, event.getEntity()
-                                        .getLastDamageCause().getCause(),
-                                player.getKiller()), String.valueOf(iLives)));
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING, player, event, iLives);
             }
 
             final List returned;
 
-            if (arena.getArenaConfig().getBoolean(
+            if (this.arena.getArenaConfig().getBoolean(
                     CFG.PLAYER_DROPSINVENTORY)) {
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
-            PACheck.handleRespawn(arena,
-                    ArenaPlayer.parsePlayer(player.getName()), returned);
+            PACheck.handleRespawn(this.arena,
+                    aPlayer, returned);
         }
     }
 
     @Override
     public void commitStart() {
-        parseStart(); // hack the team in before spawning, derp!
-        for (final ArenaTeam team : arena.getTeams()) {
-            SpawnManager.distribute(arena, team);
+        this.parseStart(); // hack the team in before spawning, derp!
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            SpawnManager.distribute(this.arena, team);
         }
     }
 
     @Override
     public void displayInfo(final CommandSender sender) {
         sender.sendMessage("normal lives: "
-                + arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES) + " || " +
+                + this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES) + " || " +
                 "infected lives: "
-                + arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
+                + this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
     }
 
     @Override
@@ -602,8 +584,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getName()) ? getLifeMap().get(aPlayer
-                            .getName()) : 0));
+                    String.valueOf(this.getLifeMap().getOrDefault(aPlayer.getName(), 0))
+            );
         }
         return res;
     }
@@ -612,8 +594,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
     public boolean hasSpawn(final String string) {
 
 
-        if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-            for (final ArenaClass aClass : arena.getClasses()) {
+        if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+            for (final ArenaClass aClass : this.arena.getClasses()) {
                 if (string.toLowerCase().startsWith(
                         aClass.getName().toLowerCase() + "spawn")) {
                     return true;
@@ -621,13 +603,13 @@ public boolean hasSpawn(final String string) {
             }
         }
 
-        return arena.isFreeForAll() && string.toLowerCase()
+        return this.arena.isFreeForAll() && string.toLowerCase()
                 .startsWith("spawn") || string.toLowerCase().startsWith("infected");
     }
 
     @Override
     public void initate(final Player player) {
-        updateLives(player, arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES));
+        this.updateLives(player, this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES));
     }
 
     @Override
@@ -639,108 +621,100 @@ public boolean isInternal() {
     public void parseLeave(final Player player) {
         if (player == null) {
             PVPArena.instance.getLogger().warning(
-                    getName() + ": player NULL");
+                    this.getName() + ": player NULL");
             return;
         }
-        if (getLifeMap().containsKey(player.getName())) {
-            getLifeMap().remove(player.getName());
-        }
+        this.getLifeMap().remove(player.getName());
     }
 
     @Override
     public void parseStart() {
-        if (arena.getTeam("infected") != null) {
+        if (this.arena.getTeam("infected") != null) {
             return;
         }
         ArenaPlayer infected = null;
         final Random random = new Random();
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             int pos = random.nextInt(team.getTeamMembers().size());
-            arena.getDebugger().i("team " + team.getName() + " random " + pos);
+            this.arena.getDebugger().i("team " + team.getName() + " random " + pos);
             for (final ArenaPlayer ap : team.getTeamMembers()) {
-                arena.getDebugger().i("#" + pos + ": " + ap, ap.getName());
-                getLifeMap().put(ap.getName(),
-                        arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES));
+                this.arena.getDebugger().i("#" + pos + ": " + ap, ap.getName());
+                this.getLifeMap().put(ap.getName(),
+                        this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_NLIVES));
                 if (pos-- == 0) {
                     infected = ap;
-                    getLifeMap().put(ap.getName(),
-                            arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
+                    this.getLifeMap().put(ap.getName(),
+                            this.arena.getArenaConfig().getInt(CFG.GOAL_INFECTED_ILIVES));
                 }
                 //break;
             }
         }
         final ArenaTeam infectedTeam = new ArenaTeam("infected", "PINK");
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             if (team.getTeamMembers().contains(infected)) {
-                final PATeamChangeEvent tcEvent = new PATeamChangeEvent(arena, infected.get(), team, infectedTeam);
+                final PATeamChangeEvent tcEvent = new PATeamChangeEvent(this.arena, infected.get(), team, infectedTeam);
                 Bukkit.getPluginManager().callEvent(tcEvent);
-                arena.updateScoreboardTeam(infected.get(), team, infectedTeam);
+                this.arena.updateScoreboardTeam(infected.get(), team, infectedTeam);
                 team.remove(infected);
             }
         }
         infectedTeam.add(infected);
 
-        final ArenaClass infectedClass = arena.getClass("%infected%");
+        final ArenaClass infectedClass = this.arena.getClass("%infected%");
         if (infectedClass != null) {
             infected.setArenaClass(infectedClass);
             InventoryManager.clearInventory(infected.get());
             infectedClass.equip(infected.get());
-            for (final ArenaModule mod : arena.getMods()) {
+            for (final ArenaModule mod : this.arena.getMods()) {
                 mod.parseRespawn(infected.get(), infectedTeam, DamageCause.CUSTOM,
                         infected.get());
             }
         }
 
-        arena.msg(infected.get(), Language.parse(arena, MSG.GOAL_INFECTED_YOU, infected.getName()));
-        arena.broadcast(Language.parse(arena, MSG.GOAL_INFECTED_PLAYER, infected.getName()));
+        this.arena.msg(infected.get(), Language.parse(this.arena, MSG.GOAL_INFECTED_YOU, infected.getName()));
+        this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_INFECTED_PLAYER, infected.getName()));
 
-        final Set spawns = new HashSet<>();
-        spawns.addAll(SpawnManager.getPASpawnsStartingWith(arena, "infected"));
+        final Set spawns = new HashSet<>(SpawnManager.getPASpawnsStartingWith(this.arena, "infected"));
 
         int pos = spawns.size();
 
         for (final PASpawn spawn : spawns) {
             if (pos-- < 0) {
-                arena.tpPlayerToCoordName(infected.get(), spawn.getName());
+                this.arena.tpPlayerToCoordName(infected, spawn.getName());
                 break;
             }
         }
-        arena.getTeams().add(infectedTeam);
+        this.arena.getTeams().add(infectedTeam);
     }
 
     @Override
     public void reset(final boolean force) {
-        endRunner = null;
-        getLifeMap().clear();
-        arena.getTeams().remove(arena.getTeam("infected"));
+        this.endRunner = null;
+        this.getLifeMap().clear();
+        this.arena.getTeams().remove(this.arena.getTeam("infected"));
     }
 
     @Override
     public void setPlayerLives(final int value) {
-        final Set plrs = new HashSet<>();
-
-        for (final String name : getLifeMap().keySet()) {
-            plrs.add(name);
-        }
+        final Set plrs = new HashSet<>(this.getLifeMap().keySet());
 
         for (final String s : plrs) {
-            getLifeMap().put(s, value);
+            this.getLifeMap().put(s, value);
         }
     }
 
     @Override
     public void setPlayerLives(final ArenaPlayer aPlayer, final int value) {
-        getLifeMap().put(aPlayer.getName(), value);
+        this.getLifeMap().put(aPlayer.getName(), value);
     }
 
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaPlayer ap : arena.getFighters()) {
-            double score = getLifeMap().containsKey(ap.getName()) ? getLifeMap().get(ap.getName())
-                    : 0;
+        for (final ArenaPlayer ap : this.arena.getFighters()) {
+            double score = this.getLifeMap().getOrDefault(ap.getName(), 0);
             if (ap.getArenaTeam() != null && "infected".equals(ap.getArenaTeam().getName())) {
-                score *= arena.getFighters().size();
+                score *= this.arena.getFighters().size();
             }
             if (scores.containsKey(ap.getName())) {
                 scores.put(ap.getName(), scores.get(ap.getName()) + score);
@@ -754,6 +728,6 @@ public Map timedEnd(final Map scores) {
 
     @Override
     public void unload(final Player player) {
-        getLifeMap().remove(player.getName());
+        this.getLifeMap().remove(player.getName());
     }
 }
diff --git a/src/net/slipcor/pvparena/goals/GoalLiberation.java b/src/net/slipcor/pvparena/goals/GoalLiberation.java
index a90ffc637..9c69998e8 100644
--- a/src/net/slipcor/pvparena/goals/GoalLiberation.java
+++ b/src/net/slipcor/pvparena/goals/GoalLiberation.java
@@ -28,12 +28,15 @@
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.event.entity.PlayerDeathEvent;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.util.Vector;
 
 import java.util.*;
 
+import static java.util.Optional.ofNullable;
+
 /**
  * 
  * Arena Goal class "Liberation"
@@ -80,9 +83,9 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Arrays.asList(new String[0]);
-        if (arena != null) {
-            for (final ArenaTeam team : arena.getTeams()) {
+        final List result = new ArrayList<>();
+        if (this.arena != null) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 result.add(sTeam + "button");
             }
@@ -413,12 +416,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                 final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
                         .getArenaTeam();
                 if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                            arena.parseDeathCause(player, event.getEntity()
-                                            .getLastDamageCause().getCause(),
-                                    player.getKiller()), String.valueOf(lives)));
+                    this.broadcastSimpleDeathMessage(player, event);
                 }
                 final List returned;
 
@@ -427,8 +425,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                     returned = InventoryManager.drop(player);
                     event.getDrops().clear();
                 } else {
-                    returned = new ArrayList<>();
-                    returned.addAll(event.getDrops());
+                    returned = new ArrayList<>(event.getDrops());
                 }
                 new InventoryRefillRunnable(arena, aPlayer.get(), returned);
 
@@ -436,7 +433,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
 
                 Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, teamName + "jail"), 1L);
 
-                arena.unKillPlayer(aPlayer.get(), aPlayer.get().getLastDamageCause() == null ? null : aPlayer.get().getLastDamageCause().getCause(), aPlayer.get().getKiller());
+                this.arena.unKillPlayer(aPlayer.get(), ofNullable(aPlayer.get().getLastDamageCause()).map(EntityDamageEvent::getCause).orElse(null), aPlayer.get().getKiller());
 
                 if (arena.getArenaConfig().getBoolean(CFG.GOAL_LIBERATION_JAILEDSCOREBOARD)) {
                     aPlayer.get().getScoreboard().getObjective("lives").getScore(aPlayer.getName()).setScore(101);
@@ -450,8 +447,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                     returned = InventoryManager.drop(player);
                     event.getDrops().clear();
                 } else {
-                    returned = new ArrayList<>();
-                    returned.addAll(event.getDrops());
+                    returned = new ArrayList<>(event.getDrops());
                 }
 
                 PACheck.handleRespawn(arena,
@@ -462,12 +458,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                 final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
                         .getArenaTeam();
                 if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                            arena.parseDeathCause(player, event.getEntity()
-                                            .getLastDamageCause().getCause(),
-                                    player.getKiller()), String.valueOf(lives)));
+                    this.broadcastSimpleDeathMessage(player, event);
                 }
 
                 PACheck.handleEnd(arena, false);
@@ -480,12 +471,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
                     .getArenaTeam();
             if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY_REMAINING,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, event.getEntity()
-                                        .getLastDamageCause().getCause(),
-                                player.getKiller()), String.valueOf(lives)));
+                this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING, player, event, lives);
             }
 
             final List returned;
@@ -495,8 +481,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
             PACheck.handleRespawn(arena,
@@ -535,8 +520,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getName()) ? getLifeMap().get(aPlayer
-                            .getName()) : 0));
+                    String.valueOf(getLifeMap().getOrDefault(aPlayer.getName(), 0))
+            );
         }
         return res;
     }
diff --git a/src/net/slipcor/pvparena/goals/GoalPhysicalFlags.java b/src/net/slipcor/pvparena/goals/GoalPhysicalFlags.java
index 8e1c035ac..a70793568 100644
--- a/src/net/slipcor/pvparena/goals/GoalPhysicalFlags.java
+++ b/src/net/slipcor/pvparena/goals/GoalPhysicalFlags.java
@@ -10,11 +10,9 @@
 import net.slipcor.pvparena.classes.PACheck;
 import net.slipcor.pvparena.commands.CommandTree;
 import net.slipcor.pvparena.commands.PAA_Region;
+import net.slipcor.pvparena.core.*;
 import net.slipcor.pvparena.core.Config.CFG;
-import net.slipcor.pvparena.core.Debug;
-import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
@@ -25,6 +23,7 @@
 import org.bukkit.ChatColor;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Player;
@@ -41,6 +40,10 @@
 import org.bukkit.util.Vector;
 
 import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.Optional.ofNullable;
 
 /**
  * 
@@ -54,26 +57,27 @@
 
 public class GoalPhysicalFlags extends ArenaGoal implements Listener {
 
-    public GoalPhysicalFlags() {
-        super("PhysicalFlags");
-        debug = new Debug(100);
-    }
-
+    private static final int PRIORITY = 7;
+    private static final String TOUCHDOWN = "touchdown";
     private Map flagMap;
+    private Map flagDataMap;
     private Map headGearMap;
 
     private String flagName = "";
 
+    public GoalPhysicalFlags() {
+        super("PhysicalFlags");
+        this.debug = new Debug(100);
+    }
+
     @Override
     public String version() {
         return PVPArena.instance.getDescription().getVersion();
     }
 
-    private static final int PRIORITY = 7;
-
     @Override
     public boolean allowsJoinInBattle() {
-        return arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
+        return this.arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
     }
 
     @Override
@@ -82,13 +86,11 @@ public PACheck checkCommand(final PACheck res, final String string) {
             return res;
         }
 
-        if ("flagtype".equalsIgnoreCase(string)
-                || "flageffect".equalsIgnoreCase(string)
-                || "touchdown".equalsIgnoreCase(string)) {
+        if ("flagtype".equalsIgnoreCase(string) || "flageffect".equalsIgnoreCase(string) || TOUCHDOWN.equalsIgnoreCase(string)) {
             res.setPriority(this, PRIORITY);
         }
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             final String sTeam = team.getName();
             if (string.contains(sTeam + "flag")) {
                 res.setPriority(this, PRIORITY);
@@ -100,9 +102,9 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Arrays.asList("flagtype", "flageffect", "touchdown");
-        if (arena != null) {
-            for (final ArenaTeam team : arena.getTeams()) {
+        final List result = Stream.of("flagtype", "flageffect", TOUCHDOWN).collect(Collectors.toList());
+        if (this.arena != null) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 result.add(sTeam + "flag");
             }
@@ -124,12 +126,12 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        final int count = TeamManager.countActiveTeams(arena);
+        final int count = TeamManager.countActiveTeams(this.arena);
 
         if (count == 1) {
             res.setPriority(this, PRIORITY); // yep. only one team left. go!
         } else if (count == 0) {
-            arena.getDebugger().i("No teams playing!");
+            this.arena.getDebugger().i("No teams playing!");
         }
 
         return res;
@@ -137,11 +139,11 @@ public PACheck checkEnd(final PACheck res) {
 
     @Override
     public String checkForMissingSpawns(final Set list) {
-        final String team = checkForMissingTeamSpawn(list);
+        final String team = this.checkForMissingTeamSpawn(list);
         if (team != null) {
             return team;
         }
-        return checkForMissingTeamCustom(list, "flag");
+        return this.checkForMissingTeamCustom(list, "flag");
     }
 
     /**
@@ -152,141 +154,128 @@ public String checkForMissingSpawns(final Set list) {
      * @param block  the block being clicked
      * @return the PACheck instance
      */
-    @SuppressWarnings("deprecation")
     @Override
     public PACheck checkInteract(final PACheck res, final Player player, final Block block) {
         if (block == null || res.getPriority() > PRIORITY) {
             return res;
         }
-        arena.getDebugger().i("checking interact", player);
+        this.arena.getDebugger().i("checking interact", player);
 
-        ItemStack flagType = StringParser.getItemStackFromString(arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGTYPE));
-        if (block.getType() != flagType.getType() || (flagType.getData().getData()>0 && flagType.getData().getData() != block.getData())) {
-            arena.getDebugger().i("block, but not flag", player);
+        Material flagType = this.arena.getArenaConfig().getMaterial(CFG.GOAL_PFLAGS_FLAGTYPE);
+        if (!ColorUtils.isSubType(block.getType(), flagType)) {
+            this.arena.getDebugger().i("block, but not flag", player);
             return res;
         }
-        arena.getDebugger().i("flag click!", player);
+        this.arena.getDebugger().i("flag click!", player);
 
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
 
-        if (getFlagMap().containsValue(player.getName())) {
-            arena.getDebugger().i("player " + player.getName() + " has got a flag", player);
+        if (this.getFlagMap().containsValue(player.getName())) {
+            this.arena.getDebugger().i("player " + player.getName() + " has got a flag", player);
 
             final Vector vLoc = block.getLocation().toVector();
             final String sTeam = aPlayer.getArenaTeam().getName();
-            arena.getDebugger().i("block: " + vLoc, player);
+            this.arena.getDebugger().i("block: " + vLoc, player);
             Vector vFlag = null;
-            if (!SpawnManager.getBlocksStartingWith(arena, sTeam + "flag").isEmpty()) {
-                vFlag = SpawnManager
-                        .getBlockNearest(
-                                SpawnManager.getBlocksStartingWith(arena, sTeam + "flag"),
-                                new PABlockLocation(player.getLocation()))
-                        .toLocation().toVector();
+            if (this.getTeamFlagLoc(sTeam) != null) {
+                vFlag = this.getTeamFlagLoc(sTeam).toLocation().toVector();
             } else {
-                arena.getDebugger().i(sTeam + "flag = null", player);
+                this.arena.getDebugger().i(sTeam + "flag = null", player);
             }
 
-            arena.getDebugger().i("player is in the team " + sTeam, player);
+            this.arena.getDebugger().i("player is in the team " + sTeam, player);
             if (vFlag != null && vLoc.distance(vFlag) < 2) {
 
-                arena.getDebugger().i("player is at his flag", player);
+                this.arena.getDebugger().i("player is at his flag", player);
 
-                if (getFlagMap().containsKey(sTeam)
-                        || getFlagMap().containsKey("touchdown")) {
-                    arena.getDebugger().i("the flag of the own team is taken!", player);
+                if (this.getFlagMap().containsKey(sTeam) || this.getFlagMap().containsKey(TOUCHDOWN)) {
+                    this.arena.getDebugger().i("the flag of the own team is taken!", player);
 
-                    if (arena.getArenaConfig().getBoolean(
-                            CFG.GOAL_FLAGS_MUSTBESAFE)
-                            && !getFlagMap().containsKey("touchdown")) {
-                        arena.getDebugger().i("cancelling", player);
+                    if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_PFLAGS_MUSTBESAFE)
+                            && !this.getFlagMap().containsKey(TOUCHDOWN)) {
+                        this.arena.getDebugger().i("cancelling", player);
 
-                        arena.msg(player,
-                                Language.parse(arena, MSG.GOAL_FLAGS_NOTSAFE));
+                        this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_FLAGS_NOTSAFE));
                         return res;
                     }
                 }
 
-                String flagTeam = getHeldFlagTeam(player.getName());
-
-                arena.getDebugger().i("the flag belongs to team " + flagTeam, player);
-
-                if (player.getItemInHand() == null
-                        || !player
-                        .getItemInHand()
-                        .getType()
-                        .name()
-                        .equals(arena.getArenaConfig().getString(
-                                CFG.GOAL_FLAGS_FLAGTYPE))) {
-                    arena.getDebugger().i("player " + player.getName()
-                            + " is not holding the flag", player);
-                    arena.msg(player,
-                            Language.parse(arena, MSG.GOAL_PHYSICALFLAGS_HOLDFLAG));
+                String flagTeam = this.getHeldFlagTeam(player.getName());
+
+                this.arena.getDebugger().i("the flag belongs to team " + flagTeam, player);
+
+                ItemStack mainHandItem = player.getInventory().getItemInMainHand();
+                if (!ColorUtils.isSubType(mainHandItem.getType(), flagType)) {
+                    this.arena.getDebugger().i("player " + player.getName() + " is not holding the flag", player);
+                    this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_PHYSICALFLAGS_HOLDFLAG));
                     return res;
                 }
 
-                player.getInventory().remove(player.getItemInHand());
+                player.getInventory().remove(mainHandItem);
                 player.updateInventory();
 
                 try {
-                    if ("touchdown".equals(flagTeam)) {
-                        arena.broadcast(Language.parse(arena,
-                                MSG.GOAL_FLAGS_TOUCHHOME, arena.getTeam(sTeam)
+                    if (TOUCHDOWN.equals(flagTeam)) {
+                        this.arena.broadcast(Language.parse(this.arena,
+                                MSG.GOAL_FLAGS_TOUCHHOME, this.arena.getTeam(sTeam)
                                         .colorizePlayer(player)
                                         + ChatColor.YELLOW, String
-                                        .valueOf(getLifeMap().get(aPlayer
+                                        .valueOf(this.getLifeMap().get(aPlayer
                                                 .getArenaTeam().getName()) - 1)));
                     } else {
-                        arena.broadcast(Language.parse(arena,
-                                MSG.GOAL_FLAGS_BROUGHTHOME, arena
+                        this.arena.broadcast(Language.parse(this.arena,
+                                MSG.GOAL_FLAGS_BROUGHTHOME, this.arena
                                         .getTeam(sTeam).colorizePlayer(player)
                                         + ChatColor.YELLOW,
-                                arena.getTeam(flagTeam).getColoredName()
+                                this.arena.getTeam(flagTeam).getColoredName()
                                         + ChatColor.YELLOW, String
-                                        .valueOf(getLifeMap().get(flagTeam) - 1)));
+                                        .valueOf(this.getLifeMap().get(flagTeam) - 1)));
                     }
-                    getFlagMap().remove(flagTeam);
+                    this.getFlagMap().remove(flagTeam);
                 } catch (final Exception e) {
                     Bukkit.getLogger().severe(
                             "[PVP Arena] team unknown/no lives: " + flagTeam);
                     e.printStackTrace();
                 }
-                if ("touchdown".equals(flagTeam)) {
-                    takeFlag(ChatColor.BLACK.name(), false,
-                            SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+                if (TOUCHDOWN.equals(flagTeam)) {
+                    this.releaseFlag(TOUCHDOWN);
                 } else {
-                    takeFlag(arena.getTeam(flagTeam).getColor().name(), false,
-                            SpawnManager.getBlockByExactName(arena, flagTeam + "flag"));
+                    this.releaseFlag(flagTeam);
                 }
-                removeEffects(player);
-                if (arena.getArenaConfig().getBoolean(
-                        CFG.GOAL_FLAGS_WOOLFLAGHEAD)) {
-                    player.getInventory().setHelmet(
-                            new ItemStack(Material.AIR, 1));
+                this.removeEffects(player);
+                if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_PFLAGS_WOOLFLAGHEAD)) {
+                    player.getInventory().setHelmet(new ItemStack(Material.AIR, 1));
                 } else {
-                    if (getHeadGearMap().get(player.getName()) == null) {
-                        player.getInventory().setHelmet(
-                                getHeadGearMap().get(player.getName()).clone());
-                        getHeadGearMap().remove(player.getName());
+                    if (this.getHeadGearMap().get(player.getName()) == null) {
+                        player.getInventory().setHelmet(this.getHeadGearMap().get(player.getName()).clone());
+                        this.getHeadGearMap().remove(player.getName());
                     }
                 }
 
-                flagTeam = "touchdown".equals(flagTeam) ? flagTeam + ':' + aPlayer
-                        .getArenaTeam().getName() : flagTeam;
+                flagTeam = TOUCHDOWN.equals(flagTeam) ? flagTeam + ':' + aPlayer.getArenaTeam().getName() : flagTeam;
 
-                reduceLivesCheckEndAndCommit(arena, flagTeam);
+                this.reduceLivesCheckEndAndCommit(this.arena, flagTeam);
 
-                final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "trigger:" + player.getName());
+                final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "trigger:" + player.getName());
                 Bukkit.getPluginManager().callEvent(gEvent);
+
+                // used to cancel block put event
+                res.setPriority(this, PRIORITY);
             }
         }
 
         return res;
     }
 
+    @Override
+    public void commitInteract(final Player player, final Block clickedBlock) {}
+
+    private PABlockLocation getTeamFlagLoc(String teamName) {
+        return SpawnManager.getBlockByExactName(this.arena, teamName + "flag");
+    }
+
     private void applyEffects(final Player player) {
-        final String value = arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGEFFECT);
+        final String value = this.arena.getArenaConfig().getString(CFG.GOAL_PFLAGS_FLAGEFFECT);
 
         if ("none".equalsIgnoreCase(value)) {
             return;
@@ -299,7 +288,7 @@ private void applyEffects(final Player player) {
         if (split.length > 1) {
             try {
                 amp = Integer.parseInt(split[1]);
-            } catch (final Exception e) {
+            } catch (final Exception ignored) {
 
             }
         }
@@ -330,12 +319,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -343,12 +332,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -360,19 +349,16 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
     @Override
     public PACheck checkSetBlock(final PACheck res, final Player player, final Block block) {
 
-        if (res.getPriority() > PRIORITY
-                || !PAA_Region.activeSelections.containsKey(player.getName())) {
+        if (res.getPriority() > PRIORITY || !PAA_Region.activeSelections.containsKey(player.getName())) {
             return res;
         }
 
-        ItemStack flagType = StringParser.getItemStackFromString(arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGTYPE));
-        if (block == null || block.getType() != flagType.getType() || (flagType.getData().getData()>0 && flagType.getData().getData() != block.getData())) {
+        Material flagType = this.arena.getArenaConfig().getMaterial(CFG.GOAL_PFLAGS_FLAGTYPE);
+        if (block == null || !ColorUtils.isSubType(block.getType(), flagType)) {
             return res;
         }
 
-        if (!PVPArena.hasAdminPerms(player)
-                && !PVPArena.hasCreatePerms(player, arena)) {
+        if (!PVPArena.hasAdminPerms(player) && !PVPArena.hasCreatePerms(player, this.arena)) {
             return res;
         }
         res.setPriority(this, PRIORITY); // success :)
@@ -428,18 +414,18 @@ private void commit(final Arena arena, final String sTeam, final boolean win) {
                             + ChatColor.YELLOW));
         }
 
-        getLifeMap().clear();
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
-                CFG.TIME_ENDCOUNTDOWN));
+        this.getLifeMap().clear();
+        this.getFlagDataMap().clear();
+        new EndRunnable(arena, arena.getArenaConfig().getInt(CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public void commitCommand(final CommandSender sender, final String[] args) {
         if ("flagtype".equalsIgnoreCase(args[0])) {
             if (args.length < 2) {
-                arena.msg(
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
+                        Language.parse(this.arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
                                 String.valueOf(args.length), "2"));
                 return;
             }
@@ -447,36 +433,36 @@ public void commitCommand(final CommandSender sender, final String[] args) {
             final Material mat = Material.getMaterial(args[1].toUpperCase());
 
             if (mat == null) {
-                arena.msg(sender,
-                        Language.parse(arena, MSG.ERROR_MAT_NOT_FOUND, args[1]));
+                this.arena.msg(sender,
+                        Language.parse(this.arena, MSG.ERROR_MAT_NOT_FOUND, args[1]));
                 return;
             }
 
-            arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGTYPE, mat.name());
+            this.arena.getArenaConfig().set(CFG.GOAL_PFLAGS_FLAGTYPE, mat.name());
 
-            arena.getArenaConfig().save();
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_TYPESET,
-                    CFG.GOAL_FLAGS_FLAGTYPE.toString()));
+            this.arena.getArenaConfig().save();
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_TYPESET,
+                    CFG.GOAL_PFLAGS_FLAGTYPE.toString()));
 
         } else if ("flageffect".equalsIgnoreCase(args[0])) {
 
             // /pa [arena] flageffect SLOW 2
             if (args.length < 2) {
-                arena.msg(
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
+                        Language.parse(this.arena, MSG.ERROR_INVALID_ARGUMENT_COUNT,
                                 String.valueOf(args.length), "2"));
                 return;
             }
 
             if ("none".equalsIgnoreCase(args[1])) {
-                arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, args[1]);
+                this.arena.getArenaConfig().set(CFG.GOAL_PFLAGS_FLAGEFFECT, args[1]);
 
-                arena.getArenaConfig().save();
-                arena.msg(
+                this.arena.getArenaConfig().save();
+                this.arena.msg(
                         sender,
-                        Language.parse(arena, MSG.SET_DONE,
-                                CFG.GOAL_FLAGS_FLAGEFFECT.getNode(), args[1]));
+                        Language.parse(this.arena, MSG.SET_DONE,
+                                CFG.GOAL_PFLAGS_FLAGEFFECT.getNode(), args[1]));
                 return;
             }
 
@@ -493,7 +479,7 @@ public void commitCommand(final CommandSender sender, final String[] args) {
             }
 
             if (pet == null) {
-                arena.msg(sender, Language.parse(arena,
+                this.arena.msg(sender, Language.parse(this.arena,
                         MSG.ERROR_POTIONEFFECTTYPE_NOTFOUND, args[1]));
                 return;
             }
@@ -504,52 +490,52 @@ public void commitCommand(final CommandSender sender, final String[] args) {
                 try {
                     amp = Integer.parseInt(args[2]);
                 } catch (final Exception e) {
-                    arena.msg(sender,
-                            Language.parse(arena, MSG.ERROR_NOT_NUMERIC, args[2]));
+                    this.arena.msg(sender,
+                            Language.parse(this.arena, MSG.ERROR_NOT_NUMERIC, args[2]));
                     return;
                 }
             }
             final String value = args[1] + 'x' + amp;
-            arena.getArenaConfig().set(CFG.GOAL_FLAGS_FLAGEFFECT, value);
+            this.arena.getArenaConfig().set(CFG.GOAL_PFLAGS_FLAGEFFECT, value);
 
-            arena.getArenaConfig().save();
-            arena.msg(
+            this.arena.getArenaConfig().save();
+            this.arena.msg(
                     sender,
-                    Language.parse(arena, MSG.SET_DONE,
-                            CFG.GOAL_FLAGS_FLAGEFFECT.getNode(), value));
+                    Language.parse(this.arena, MSG.SET_DONE,
+                            CFG.GOAL_PFLAGS_FLAGEFFECT.getNode(), value));
 
         } else if (args[0].contains("flag")) {
-            for (final ArenaTeam team : arena.getTeams()) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 if (args[0].contains(sTeam + "flag")) {
-                    flagName = args[0];
-                    PAA_Region.activeSelections.put(sender.getName(), arena);
+                    this.flagName = args[0];
+                    PAA_Region.activeSelections.put(sender.getName(), this.arena);
 
-                    arena.msg(sender,
-                            Language.parse(arena, MSG.GOAL_FLAGS_TOSET, flagName));
+                    this.arena.msg(sender,
+                            Language.parse(this.arena, MSG.GOAL_FLAGS_TOSET, this.flagName));
                 }
             }
-        } else if ("touchdown".equalsIgnoreCase(args[0])) {
-            flagName = args[0] + "flag";
-            PAA_Region.activeSelections.put(sender.getName(), arena);
+        } else if (TOUCHDOWN.equalsIgnoreCase(args[0])) {
+            this.flagName = args[0] + "flag";
+            PAA_Region.activeSelections.put(sender.getName(), this.arena);
 
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_FLAGS_TOSET, flagName));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_FLAGS_TOSET, this.flagName));
         }
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[FLAGS] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[FLAGS] already ending");
             return;
         }
-        arena.getDebugger().i("[FLAGS]");
+        this.arena.getDebugger().i("[FLAGS]");
 
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
         ArenaTeam aTeam = null;
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() == Status.FIGHT) {
                     aTeam = team;
@@ -560,40 +546,38 @@ public void commitEnd(final boolean force) {
 
         if (aTeam != null && !force) {
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "END");
 
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "WINNER");
-            arena.broadcast(Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+            this.arena.broadcast(Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                     + aTeam.getName() + ChatColor.YELLOW));
         }
 
-        if (ArenaModuleManager.commitEnd(arena, aTeam)) {
+        if (ArenaModuleManager.commitEnd(this.arena, aTeam)) {
             return;
         }
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
-                CFG.TIME_ENDCOUNTDOWN));
+        new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public boolean commitSetFlag(final Player player, final Block block) {
 
-        arena.getDebugger().i("trying to set a flag", player);
+        this.arena.getDebugger().i("trying to set a flag", player);
 
         // command : /pa redflag1
         // location: red1flag:
 
-        SpawnManager.setBlock(arena, new PABlockLocation(block.getLocation()),
-                flagName);
+        SpawnManager.setBlock(this.arena, new PABlockLocation(block.getLocation()), this.flagName);
 
-        arena.msg(player, Language.parse(arena, MSG.GOAL_FLAGS_SET, flagName));
+        this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_FLAGS_SET, this.flagName));
 
         PAA_Region.activeSelections.remove(player.getName());
-        flagName = "";
+        this.flagName = "";
 
         return true;
     }
@@ -609,82 +593,81 @@ public void configParse(final YamlConfiguration config) {
 
     @Override
     public void disconnect(final ArenaPlayer aPlayer) {
-        if (getFlagMap() == null) {
+        if (this.getFlagMap().isEmpty()) {
             return;
         }
-        final String sTeam = getHeldFlagTeam(aPlayer.getName());
-        final ArenaTeam flagTeam = arena.getTeam(sTeam);
+        final String sTeam = this.getHeldFlagTeam(aPlayer.getName());
+        final ArenaTeam flagTeam = this.arena.getTeam(sTeam);
 
         if (flagTeam == null) {
             if (sTeam != null) {
-                arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
+                this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
                         .getArenaTeam().getColorCodeString()
                         + aPlayer.getName()
                         + ChatColor.YELLOW));
 
-                getFlagMap().remove("touchdown");
-                if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+                this.getFlagMap().remove(TOUCHDOWN);
+                if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
                     if (aPlayer.get() != null) {
                         aPlayer.get().getInventory()
-                                .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                                .setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
                     }
-                    getHeadGearMap().remove(aPlayer.getName());
+                    this.getHeadGearMap().remove(aPlayer.getName());
                 }
 
-                takeFlag(ChatColor.BLACK.name(), false,
-                        SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+                this.releaseFlag(TOUCHDOWN);
             }
         } else {
-            arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
                     .getArenaTeam().getColorCodeString()
                     + aPlayer.getName()
                     + ChatColor.YELLOW, flagTeam.getName() + ChatColor.YELLOW));
-            getFlagMap().remove(flagTeam.getName());
-            if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+            this.getFlagMap().remove(flagTeam.getName());
+            if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
                 if (aPlayer.get() != null) {
                     aPlayer.get().getInventory()
-                            .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                            .setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
                 }
-                getHeadGearMap().remove(aPlayer.getName());
+                this.getHeadGearMap().remove(aPlayer.getName());
             }
 
-            takeFlag(flagTeam.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, flagTeam.getName() + "flag"));
+            this.releaseFlag(flagTeam.getName());
         }
     }
 
     @Override
     public void displayInfo(final CommandSender sender) {
-        sender.sendMessage("flageffect: " +
-                arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGEFFECT));
-        sender.sendMessage("flagtype: " +
-                arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGTYPE));
-        sender.sendMessage("lives: " +
-                arena.getArenaConfig().getInt(CFG.GOAL_FLAGS_LIVES));
-        sender.sendMessage(StringParser.colorVar("mustbesafe",
-                arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_MUSTBESAFE)) +
-                " | " + StringParser.colorVar("flaghead",
-                arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)));
+        Config cfg = this.arena.getArenaConfig();
+        sender.sendMessage("flageffect: " + cfg.getString(CFG.GOAL_PFLAGS_FLAGEFFECT));
+        sender.sendMessage("flagtype: " + cfg.getString(CFG.GOAL_PFLAGS_FLAGTYPE));
+        sender.sendMessage("lives: " + cfg.getInt(CFG.GOAL_PFLAGS_LIVES));
+        sender.sendMessage(StringParser.colorVar("mustbesafe", cfg.getBoolean(CFG.GOAL_PFLAGS_MUSTBESAFE))
+                + " | " + StringParser.colorVar("flaghead", cfg.getBoolean(CFG.GOAL_PFLAGS_WOOLFLAGHEAD)));
     }
 
     private Map getFlagMap() {
-        if (flagMap == null) {
-            flagMap = new HashMap<>();
+        if (this.flagMap == null) {
+            this.flagMap = new HashMap<>();
+        }
+        return this.flagMap;
+    }
+
+    private Map getFlagDataMap() {
+        if (this.flagDataMap == null) {
+            this.flagDataMap = new HashMap<>();
         }
-        return flagMap;
+        return this.flagDataMap;
     }
 
-    private short getFlagOverrideTeamShort(final Arena arena, final String team) {
+    private Material getFlagOverrideTeamMaterial(final Arena arena, final String team) {
         if (arena.getArenaConfig().getUnsafe("flagColors." + team) == null) {
-            if ("touchdown".equals(team)) {
-                return StringParser
-                        .getColorDataFromENUM(ChatColor.BLACK.name());
+            if (TOUCHDOWN.equals(team)) {
+                return ColorUtils.getWoolMaterialFromChatColor(ChatColor.BLACK);
             }
-            return StringParser.getColorDataFromENUM(arena.getTeam(team)
-                    .getColor().name());
+            return ColorUtils.getWoolMaterialFromChatColor(arena.getTeam(team).getColor());
         }
-        return StringParser.getColorDataFromENUM((String) arena
-                .getArenaConfig().getUnsafe("flagColors." + team));
+        return ColorUtils.getWoolMaterialFromDyeColor(
+                (String) arena.getArenaConfig().getUnsafe("flagColors." + team));
     }
 
     @Override
@@ -692,18 +675,17 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam()
-                            .getName()) ? getLifeMap().get(aPlayer
-                            .getArenaTeam().getName()) : 0));
+                    String.valueOf(this.getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
 
     private Map getHeadGearMap() {
-        if (headGearMap == null) {
-            headGearMap = new HashMap<>();
+        if (this.headGearMap == null) {
+            this.headGearMap = new HashMap<>();
         }
-        return headGearMap;
+        return this.headGearMap;
     }
 
     /**
@@ -713,15 +695,14 @@ private Map getHeadGearMap() {
      * @return a team name
      */
     private String getHeldFlagTeam(final String player) {
-        if (getFlagMap().size() < 1) {
+        if (this.getFlagMap().isEmpty()) {
             return null;
         }
 
-        arena.getDebugger().i("getting held FLAG of player " + player, player);
-        for (final String sTeam : getFlagMap().keySet()) {
-            arena.getDebugger().i("team " + sTeam + " is in " + getFlagMap().get(sTeam)
-                    + "s hands", player);
-            if (player.equals(getFlagMap().get(sTeam))) {
+        this.arena.getDebugger().i("getting held FLAG of player " + player, player);
+        for (final String sTeam : this.getFlagMap().keySet()) {
+            this.arena.getDebugger().i("team " + sTeam + " is in " + this.getFlagMap().get(sTeam) + "s hands", player);
+            if (player.equals(this.getFlagMap().get(sTeam))) {
                 return sTeam;
             }
         }
@@ -730,7 +711,7 @@ private String getHeldFlagTeam(final String player) {
 
     @Override
     public boolean hasSpawn(final String string) {
-        for (final String teamName : arena.getTeamNames()) {
+        for (final String teamName : this.arena.getTeamNames()) {
             if (string.toLowerCase().equals(teamName.toLowerCase() + "flag")) {
                 return true;
             }
@@ -739,8 +720,8 @@ public boolean hasSpawn(final String string) {
                 return true;
             }
 
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(teamName.toLowerCase() +
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -755,14 +736,8 @@ public boolean hasSpawn(final String string) {
     public void initate(final Player player) {
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
         final ArenaTeam team = aPlayer.getArenaTeam();
-        if (!getLifeMap().containsKey(team.getName())) {
-            getLifeMap().put(aPlayer.getArenaTeam().getName(), arena.getArenaConfig()
-                    .getInt(CFG.GOAL_FLAGS_LIVES));
-
-            takeFlag(team.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, team.getName() + "flag"));
-            takeFlag(ChatColor.BLACK.name(), false,
-                    SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+        if (!this.getLifeMap().containsKey(team.getName())) {
+            this.getLifeMap().put(aPlayer.getArenaTeam().getName(), this.arena.getArenaConfig().getInt(CFG.GOAL_PFLAGS_LIVES));
         }
     }
 
@@ -775,101 +750,94 @@ public boolean isInternal() {
     public void parsePlayerDeath(final Player player,
                                  final EntityDamageEvent lastDamageCause) {
 
-        if (getFlagMap() == null) {
-            arena.getDebugger().i("no flags set!!", player);
+        if (this.getFlagMap().isEmpty()) {
+            this.arena.getDebugger().i("no flags set!!", player);
             return;
         }
-        final String sTeam = getHeldFlagTeam(player.getName());
-        final ArenaTeam flagTeam = arena.getTeam(sTeam);
+        final String sTeam = this.getHeldFlagTeam(player.getName());
+        final ArenaTeam flagTeam = this.arena.getTeam(sTeam);
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
 
         if (flagTeam == null) {
             if (sTeam != null) {
-                arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
+                this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPEDTOUCH, aPlayer
                         .getArenaTeam().getColorCodeString()
                         + aPlayer.getName()
                         + ChatColor.YELLOW));
 
-                getFlagMap().remove("touchdown");
-                if (getHeadGearMap() != null && getHeadGearMap().get(aPlayer.getName()) != null) {
+                this.getFlagMap().remove(TOUCHDOWN);
+                if (this.getHeadGearMap() != null && this.getHeadGearMap().get(aPlayer.getName()) != null) {
                     if (aPlayer.get() != null) {
-                        aPlayer.get().getInventory()
-                                .setHelmet(getHeadGearMap().get(aPlayer.getName()).clone());
+                        aPlayer.get().getInventory().setHelmet(this.getHeadGearMap().get(aPlayer.getName()).clone());
                     }
-                    getHeadGearMap().remove(aPlayer.getName());
+                    this.getHeadGearMap().remove(aPlayer.getName());
                 }
 
-                takeFlag(ChatColor.BLACK.name(), false,
-                        SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+                this.releaseFlag(TOUCHDOWN);
             }
         } else {
-            arena.broadcast(Language.parse(arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
+            this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_FLAGS_DROPPED, aPlayer
                             .getArenaTeam().colorizePlayer(player) + ChatColor.YELLOW,
                     flagTeam.getColoredName() + ChatColor.YELLOW));
-            getFlagMap().remove(flagTeam.getName());
-            if (getHeadGearMap() != null
-                    && getHeadGearMap().get(player.getName()) != null) {
-                player.getInventory().setHelmet(
-                        getHeadGearMap().get(player.getName()).clone());
-                getHeadGearMap().remove(player.getName());
+            this.getFlagMap().remove(flagTeam.getName());
+            if (this.getHeadGearMap() != null && this.getHeadGearMap().get(player.getName()) != null) {
+                player.getInventory().setHelmet(this.getHeadGearMap().get(player.getName()).clone());
+                this.getHeadGearMap().remove(player.getName());
             }
 
-            takeFlag(flagTeam.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, flagTeam.getName() + "flag"));
+            this.releaseFlag(flagTeam.getName());
         }
     }
 
     @Override
     public void parseStart() {
-        getLifeMap().clear();
-        for (final ArenaTeam team : arena.getTeams()) {
+        this.getLifeMap().clear();
+        this.getFlagDataMap().clear();
+        for (final ArenaTeam team : this.arena.getTeams()) {
             if (!team.getTeamMembers().isEmpty()) {
-                arena.getDebugger().i("adding team " + team.getName());
+                this.arena.getDebugger().i("adding team " + team.getName());
                 // team is active
-                getLifeMap().put(team.getName(),
-                        arena.getArenaConfig().getInt(CFG.GOAL_FLAGS_LIVES, 3));
+                this.getLifeMap().put(team.getName(), this.arena.getArenaConfig().getInt(CFG.GOAL_PFLAGS_LIVES, 3));
+                Block flagBlock = this.getTeamFlagLoc(team.getName()).toLocation().getBlock();
+                this.getFlagDataMap().put(team.getName(), flagBlock.getBlockData().clone());
             }
-            takeFlag(team.getColor().name(), false,
-                    SpawnManager.getBlockByExactName(arena, team.getName() + "flag"));
         }
-        takeFlag(ChatColor.BLACK.name(), false,
-                SpawnManager.getBlockByExactName(arena, "touchdownflag"));
+        ofNullable(this.getTeamFlagLoc(TOUCHDOWN)).ifPresent(paBlockLocation -> {
+            Block touchdownFlagBlock = paBlockLocation.toLocation().getBlock();
+            this.getFlagDataMap().put(TOUCHDOWN, touchdownFlagBlock.getBlockData().clone());
+        });
     }
 
-    private boolean reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
+    private void reduceLivesCheckEndAndCommit(final Arena arena, final String team) {
 
         arena.getDebugger().i("reducing lives of team " + team);
-        if (getLifeMap().get(team) == null) {
+        if (this.getLifeMap().get(team) == null) {
             if (team.contains(":")) {
                 final String realTeam = team.split(":")[1];
-                final int iLives = getLifeMap().get(realTeam) - 1;
+                final int iLives = this.getLifeMap().get(realTeam) - 1;
                 if (iLives > 0) {
-                    getLifeMap().put(realTeam, iLives);
+                    this.getLifeMap().put(realTeam, iLives);
                 } else {
-                    getLifeMap().remove(realTeam);
-                    commit(arena, realTeam, true);
-                    return true;
+                    this.getLifeMap().remove(realTeam);
+                    this.commit(arena, realTeam, true);
                 }
             }
         } else {
-            if (getLifeMap().get(team) != null) {
-                final int iLives = getLifeMap().get(team) - 1;
+            if (this.getLifeMap().get(team) != null) {
+                final int iLives = this.getLifeMap().get(team) - 1;
                 if (iLives > 0) {
-                    getLifeMap().put(team, iLives);
+                    this.getLifeMap().put(team, iLives);
                 } else {
-                    getLifeMap().remove(team);
-                    commit(arena, team, false);
-                    return true;
+                    this.getLifeMap().remove(team);
+                    this.commit(arena, team, false);
                 }
             }
         }
-
-        return false;
     }
 
     private void removeEffects(final Player player) {
-        final String value = arena.getArenaConfig().getString(
-                CFG.GOAL_FLAGS_FLAGEFFECT);
+        final String value = this.arena.getArenaConfig().getString(
+                CFG.GOAL_PFLAGS_FLAGEFFECT);
 
         if ("none".equalsIgnoreCase(value)) {
             return;
@@ -890,8 +858,7 @@ private void removeEffects(final Player player) {
         }
 
         if (pet == null) {
-            PVPArena.instance.getLogger().warning(
-                    "Invalid Potion Effect Definition: " + value);
+            PVPArena.instance.getLogger().warning("Invalid Potion Effect Definition: " + value);
             return;
         }
 
@@ -901,14 +868,21 @@ private void removeEffects(final Player player) {
 
     @Override
     public void reset(final boolean force) {
-        getFlagMap().clear();
-        getHeadGearMap().clear();
-        getLifeMap().clear();
+        this.getHeadGearMap().clear();
+        this.getLifeMap().clear();
+        this.getFlagMap().clear();
+        if(!this.getFlagDataMap().isEmpty()) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
+                this.releaseFlag(team.getName());
+            }
+            this.releaseFlag(TOUCHDOWN);
+        }
+        this.getFlagDataMap().clear();
     }
 
     @Override
     public void setDefaults(final YamlConfiguration config) {
-        if (arena.isFreeForAll()) {
+        if (this.arena.isFreeForAll()) {
             return;
         }
 
@@ -916,58 +890,42 @@ public void setDefaults(final YamlConfiguration config) {
             config.set("teams", null);
         }
         if (config.get("teams") == null) {
-            arena.getDebugger().i("no teams defined, adding custom red and blue!");
+            this.arena.getDebugger().i("no teams defined, adding custom red and blue!");
             config.addDefault("teams.red", ChatColor.RED.name());
             config.addDefault("teams.blue", ChatColor.BLUE.name());
         }
-        if (arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)
+        if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_PFLAGS_WOOLFLAGHEAD)
                 && config.get("flagColors") == null) {
-            arena.getDebugger().i("no flagheads defined, adding white and black!");
+            this.arena.getDebugger().i("no flagheads defined, adding white and black!");
             config.addDefault("flagColors.red", "WHITE");
             config.addDefault("flagColors.blue", "BLACK");
         }
     }
 
     /**
-     * take/reset an arena flag
+     * reset an arena flag
      *
-     * @param flagColor       the teamcolor to reset
-     * @param take            true if take, else reset
-     * @param paBlockLocation the location to take/reset
+     * @param teamName  team whose flag needs to be reset
      */
-    void takeFlag(final String flagColor, final boolean take, final PABlockLocation paBlockLocation) {
+    private void releaseFlag(final String teamName) {
+        PABlockLocation paBlockLocation = this.getTeamFlagLoc(teamName);
         if (paBlockLocation == null) {
             return;
         }
-        if (!"WOOL".equals(arena.getArenaConfig().getString(CFG.GOAL_FLAGS_FLAGTYPE))) {
-            paBlockLocation.toLocation()
-                    .getBlock()
-                    .setType(
-                            take ? Material.BEDROCK : Material.valueOf(arena
-                                    .getArenaConfig().getString(
-                                            CFG.GOAL_FLAGS_FLAGTYPE)));
-            return;
-        }
-        if (take) {
-            paBlockLocation.toLocation().getBlock()
-                    .setData(StringParser.getColorDataFromENUM("WHITE"));
-        } else {
-            paBlockLocation.toLocation()
-                    .getBlock()
-                    .setTypeIdAndData(
-                            Material.valueOf(
-                                    arena.getArenaConfig().getString(
-                                            CFG.GOAL_FLAGS_FLAGTYPE)).getId(),
-                            StringParser.getColorDataFromENUM(flagColor), false);
+
+        Block flagBlock = paBlockLocation.toLocation().getBlock();
+        try {
+            flagBlock.setBlockData(this.getFlagDataMap().get(teamName));
+        } catch (Exception e) {
+            PVPArena.instance.getLogger().warning("Impossible to reset flag data ! You may recreate arena flags.");
         }
     }
 
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaTeam team : arena.getTeams()) {
-            double score = getLifeMap().containsKey(team.getName()) ? getLifeMap()
-                    .get(team.getName()) : 0;
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            double score = this.getLifeMap().getOrDefault(team.getName(), 0);
             if (scores.containsKey(team.getName())) {
                 scores.put(team.getName(), scores.get(team.getName()) + score);
             } else {
@@ -980,115 +938,97 @@ public Map timedEnd(final Map scores) {
 
     @Override
     public void unload(final Player player) {
-        disconnect(ArenaPlayer.parsePlayer(player.getName()));
-        if (allowsJoinInBattle()) {
-            arena.hasNotPlayed(ArenaPlayer.parsePlayer(player.getName()));
+        this.disconnect(ArenaPlayer.parsePlayer(player.getName()));
+        if (this.allowsJoinInBattle()) {
+            this.arena.hasNotPlayed(ArenaPlayer.parsePlayer(player.getName()));
         }
     }
 
-    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
     public void onFlagClaim(final BlockBreakEvent event) {
         final Player player = event.getPlayer();
-        if (!arena.hasPlayer(event.getPlayer())
-                || !event
-                .getBlock()
-                .getType()
-                .name()
-                .equals(arena.getArenaConfig().getString(
-                        CFG.GOAL_FLAGS_FLAGTYPE))) {
-
-            arena.getDebugger().i("block destroy, ignoring", player);
-            arena.getDebugger().i(String.valueOf(arena.hasPlayer(event.getPlayer())), player);
-            arena.getDebugger().i(event.getBlock().getType().name(), player);
+        Material brokenMaterial = event.getBlock().getType();
+        if (!this.arena.hasPlayer(event.getPlayer()) ||
+                !ColorUtils.isSubType(brokenMaterial, this.arena.getArenaConfig().getMaterial(CFG.GOAL_PFLAGS_FLAGTYPE))) {
+
+            this.arena.getDebugger().i("block destroy, ignoring", player);
+            this.arena.getDebugger().i(String.valueOf(this.arena.hasPlayer(event.getPlayer())), player);
+            this.arena.getDebugger().i(event.getBlock().getType().name(), player);
             return;
         }
 
         final Block block = event.getBlock();
 
-        arena.getDebugger().i("flag destroy!", player);
+        this.arena.getDebugger().i("flag destroy!", player);
 
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
 
-        if (getFlagMap().containsValue(player.getName())) {
-            arena.getDebugger().i("already carries a flag!", player);
+        if (this.getFlagMap().containsValue(player.getName())) {
+            this.arena.getDebugger().i("already carries a flag!", player);
             return;
         }
         final ArenaTeam pTeam = aPlayer.getArenaTeam();
         if (pTeam == null) {
             return;
         }
-        final Set setTeam = new HashSet<>();
 
-        for (final ArenaTeam team : arena.getTeams()) {
-            setTeam.add(team);
-        }
-        setTeam.add(new ArenaTeam("touchdown", "BLACK"));
+        final Set setTeam = new HashSet<>(this.arena.getTeams());
+
+        setTeam.add(new ArenaTeam(TOUCHDOWN, "BLACK"));
         Vector vFlag = null;
         for (final ArenaTeam team : setTeam) {
-            final String aTeam = team.getName();
+            final String teamName = team.getName();
+            final PABlockLocation teamFlagLoc = this.getTeamFlagLoc(teamName);
 
-            if (aTeam.equals(pTeam.getName())) {
-                arena.getDebugger().i("equals!OUT! ", player);
+            if (teamName.equals(pTeam.getName())) {
+                this.arena.getDebugger().i("equals!OUT! ", player);
                 continue;
             }
-            if (team.getTeamMembers().size() < 1
-                    && !"touchdown".equals(team.getName())) {
-                arena.getDebugger().i("size!OUT! ", player);
+            if (team.getTeamMembers().size() < 1 && !TOUCHDOWN.equals(team.getName())) {
+                this.arena.getDebugger().i("size!OUT! ", player);
                 continue; // dont check for inactive teams
             }
-            if (getFlagMap() != null && getFlagMap().containsKey(aTeam)) {
-                arena.getDebugger().i("taken!OUT! ", player);
+            if (this.getFlagMap().containsKey(teamName)) {
+                this.arena.getDebugger().i("taken!OUT! ", player);
                 continue; // already taken
             }
-            arena.getDebugger().i("checking for flag of team " + aTeam, player);
+            this.arena.getDebugger().i("checking for flag of team " + teamName, player);
             Vector vLoc = block.getLocation().toVector();
-            arena.getDebugger().i("block: " + vLoc, player);
-            if (!SpawnManager.getBlocksStartingWith(arena, aTeam + "flag").isEmpty()) {
-                vFlag = SpawnManager
-                        .getBlockNearest(
-                                SpawnManager.getBlocksStartingWith(arena, aTeam
-                                        + "flag"),
-                                new PABlockLocation(player.getLocation()))
-                        .toLocation().toVector();
-            }
-            if (vFlag != null && vLoc.distance(vFlag) < 2) {
-                arena.getDebugger().i("flag found!", player);
-                arena.getDebugger().i("vFlag: " + vFlag, player);
+            this.arena.getDebugger().i("block: " + vLoc, player);
+
+            if(teamFlagLoc != null && vLoc.equals(teamFlagLoc.toLocation().toVector())) {
+                this.arena.getDebugger().i("flag found!", player);
+                this.arena.getDebugger().i("vFlag: " + vFlag, player);
 
-                if ("touchdown".equals(team.getName())) {
+                if (TOUCHDOWN.equals(team.getName())) {
 
-                    arena.broadcast(Language.parse(arena,
+                    this.arena.broadcast(Language.parse(this.arena,
                             MSG.GOAL_FLAGS_GRABBEDTOUCH,
                             pTeam.colorizePlayer(player) + ChatColor.YELLOW));
                 } else {
 
-                    arena.broadcast(Language
-                            .parse(arena, MSG.GOAL_FLAGS_GRABBED,
+                    this.arena.broadcast(Language
+                            .parse(this.arena, MSG.GOAL_FLAGS_GRABBED,
                                     pTeam.colorizePlayer(player)
                                             + ChatColor.YELLOW,
                                     team.getColoredName()
                                             + ChatColor.YELLOW));
                 }
                 try {
-                    getHeadGearMap().put(player.getName(), player.getInventory()
-                            .getHelmet().clone());
-                } catch (final Exception e) {
+                    this.getHeadGearMap().put(player.getName(), player.getInventory().getHelmet().clone());
+                } catch (final Exception ignored) {
 
                 }
-                final ItemStack itemStack = block.getState().getData().toItemStack()
-                        .clone();
-                itemStack.setAmount(1);
-                if (arena.getArenaConfig().getBoolean(
-                        CFG.GOAL_FLAGS_WOOLFLAGHEAD)) {
-                    itemStack.setDurability(getFlagOverrideTeamShort(arena, aTeam));
-                }
-                player.getInventory().setHelmet(itemStack);
-                applyEffects(player);
-
-                takeFlag(team.getColor().name(), true,
-                        new PABlockLocation(block.getLocation()));
-                getFlagMap().put(aTeam, player.getName());
 
+                if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_PFLAGS_WOOLFLAGHEAD)) {
+                    final ItemStack itemStack = new ItemStack(this.getFlagOverrideTeamMaterial(this.arena, teamName));
+                    player.getInventory().setHelmet(itemStack);
+                }
+                this.applyEffects(player);
+                this.getFlagMap().put(teamName, player.getName());
+                player.getInventory().addItem(new ItemStack(block.getType()));
+                block.setType(Material.AIR);;
+                event.setCancelled(true);
                 return;
             }
         }
@@ -1104,13 +1044,11 @@ public void onInventoryClick(final InventoryClickEvent event) {
             return;
         }
 
-        if (event.isCancelled()
-                || getHeldFlagTeam(player.getName()) == null) {
+        if (event.isCancelled() || this.getHeldFlagTeam(player.getName()) == null) {
             return;
         }
 
-        if (event.getInventory().getType() == InventoryType.CRAFTING
-                && event.getRawSlot() != 5) {
+        if (event.getInventory().getType() == InventoryType.CRAFTING && event.getRawSlot() != 5) {
             return;
         }
 
diff --git a/src/net/slipcor/pvparena/goals/GoalPlayerDeathMatch.java b/src/net/slipcor/pvparena/goals/GoalPlayerDeathMatch.java
index db50dc2e7..1bfd6208c 100644
--- a/src/net/slipcor/pvparena/goals/GoalPlayerDeathMatch.java
+++ b/src/net/slipcor/pvparena/goals/GoalPlayerDeathMatch.java
@@ -18,7 +18,6 @@
 import net.slipcor.pvparena.managers.InventoryManager;
 import net.slipcor.pvparena.runnables.EndRunnable;
 import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.event.entity.PlayerDeathEvent;
@@ -170,13 +169,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             Bukkit.getPluginManager().callEvent(gEvent);
 
             if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
-                        .getArenaTeam();
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, event.getEntity()
-                                .getLastDamageCause().getCause(), player)));
+                this.broadcastSimpleDeathMessage(player, event);
             }
 
             final List returned;
@@ -186,8 +179,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
             PACheck.handleRespawn(arena, ArenaPlayer.parsePlayer(player.getName()), returned);
@@ -214,24 +206,12 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             return;
         }
 
-        final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
-                .getArenaTeam();
-        if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY_REMAINING_FRAGS,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, player
-                                .getLastDamageCause().getCause(), killer),
-                        String.valueOf(iLives-1)));
+        if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
+                this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING_FRAGS, player, event, iLives-1);
             } else {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, player
-                                .getLastDamageCause().getCause(), killer)));
+                this.broadcastSimpleDeathMessage(player, event);
             }
-
         }
 
         final List returned;
@@ -241,8 +221,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             returned = InventoryManager.drop(player);
             event.getDrops().clear();
         } else {
-            returned = new ArrayList<>();
-            returned.addAll(event.getDrops());
+            returned = new ArrayList<>(event.getDrops());
         }
 
         PACheck.handleRespawn(arena, ArenaPlayer.parsePlayer(player.getName()), returned);
diff --git a/src/net/slipcor/pvparena/goals/GoalPlayerKillReward.java b/src/net/slipcor/pvparena/goals/GoalPlayerKillReward.java
index 1cca88fa6..09d910d05 100644
--- a/src/net/slipcor/pvparena/goals/GoalPlayerKillReward.java
+++ b/src/net/slipcor/pvparena/goals/GoalPlayerKillReward.java
@@ -13,7 +13,6 @@
 import net.slipcor.pvparena.core.Debug;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
@@ -23,6 +22,7 @@
 import net.slipcor.pvparena.runnables.EndRunnable;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
+import org.bukkit.Material;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.configuration.file.YamlConfiguration;
@@ -32,6 +32,8 @@
 
 import java.util.*;
 
+import static net.slipcor.pvparena.core.Utils.getSerializableItemStacks;
+
 /**
  * 
  * Arena Goal class "PlayerKillreward"
@@ -47,10 +49,10 @@
 public class GoalPlayerKillReward extends ArenaGoal {
     public GoalPlayerKillReward() {
         super("PlayerKillReward");
-        debug = new Debug(102);
+        this.debug = new Debug(102);
     }
 
-    private Map itemMap;
+    private Map itemMapCubed;
 
     private EndRunnable endRunner;
 
@@ -63,7 +65,7 @@ public String version() {
 
     @Override
     public boolean allowsJoinInBattle() {
-        return arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
+        return this.arena.getArenaConfig().getBoolean(CFG.PERMS_JOININBATTLE);
     }
 
     @Override
@@ -99,8 +101,8 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final int count = TeamManager.countActiveTeams(arena);
+        if (!this.arena.isFreeForAll()) {
+            final int count = TeamManager.countActiveTeams(this.arena);
 
             if (count <= 1) {
                 res.setPriority(this, PRIORITY); // yep. only one team left. go!
@@ -108,7 +110,7 @@ public PACheck checkEnd(final PACheck res) {
             return res;
         }
 
-        final int count = getLifeMap().size();
+        final int count = this.getLifeMap().size();
 
         if (count <= 1) {
             res.setPriority(this, PRIORITY); // yep. only one player left. go!
@@ -122,11 +124,11 @@ public PACheck checkEnd(final PACheck res) {
 
     @Override
     public String checkForMissingSpawns(final Set list) {
-        if (!arena.isFreeForAll()) {
-            return checkForMissingTeamSpawn(list);
+        if (!this.arena.isFreeForAll()) {
+            return this.checkForMissingTeamSpawn(list);
         }
 
-        return checkForMissingSpawn(list);
+        return this.checkForMissingSpawn(list);
     }
 
     @Override
@@ -135,12 +137,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -148,12 +150,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -164,7 +166,7 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
 
     @Override
     public void commitCommand(final CommandSender sender, final String[] args) {
-        if (!AbstractArenaCommand.argCountValid(sender, arena, args, new Integer[]{2,
+        if (!AbstractArenaCommand.argCountValid(sender, this.arena, args, new Integer[]{2,
                 3})) {
             return;
         }
@@ -176,102 +178,96 @@ public void commitCommand(final CommandSender sender, final String[] args) {
         try {
             value = Integer.parseInt(args[1]);
         } catch (final Exception e) {
-            arena.msg(sender, Language.parse(arena, MSG.ERROR_NOT_NUMERIC, args[1]));
+            this.arena.msg(sender, Language.parse(this.arena, MSG.ERROR_NOT_NUMERIC, args[1]));
             return;
         }
         if (args.length > 2) {
-            getItemMap().remove(value);
-            arena.msg(sender,
-                    Language.parse(arena, MSG.GOAL_KILLREWARD_REMOVED, args[1]));
+            this.getItemMap().remove(value);
+            this.arena.msg(sender,
+                    Language.parse(this.arena, MSG.GOAL_KILLREWARD_REMOVED, args[1]));
         } else {
             if (!(sender instanceof Player)) {
-                Arena.pmsg(sender, Language.parse(arena, MSG.ERROR_ONLY_PLAYERS));
+                Arena.pmsg(sender, Language.parse(this.arena, MSG.ERROR_ONLY_PLAYERS));
                 return;
             }
             final Player player = (Player) sender;
-            final String contents = StringParser.getStringFromItemStacks(player
-                    .getInventory().getArmorContents())
-                    + ','
-                    + StringParser.getStringFromItemStacks(player.getInventory()
-                    .getStorageContents())
-                    + ','
-                    + StringParser.getStringFromItemStack(player.getInventory()
-                    .getItemInOffHand());
 
-            getItemMap().put(value, StringParser.getItemStacksFromString(contents));
-            arena.msg(sender, Language.parse(arena, MSG.GOAL_KILLREWARD_ADDED,
-                    args[1], contents));
+            ItemStack[][] content = new ItemStack[][]{
+                    player.getInventory().getStorageContents(),
+                    new ItemStack[]{player.getInventory().getItemInOffHand()},
+                    player.getInventory().getArmorContents()
+            };
+
+            this.getItemMap().put(value, content);
+            this.arena.msg(sender, Language.parse(this.arena, MSG.GOAL_KILLREWARD_ADDED,
+                    args[1]));
 
         }
 
-        saveItems();
+        this.saveItems();
     }
 
     @Override
     public void commitEnd(final boolean force) {
-        if (endRunner != null) {
+        if (this.endRunner != null) {
             return;
         }
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[PKW] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[PKW] already ending");
             return;
         }
-        final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "");
+        final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "");
         Bukkit.getPluginManager().callEvent(gEvent);
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() != Status.FIGHT) {
                     continue;
                 }
 
-                if (arena.isFreeForAll()) {
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.PLAYER_HAS_WON, ap.getName()),
+                if (this.arena.isFreeForAll()) {
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.PLAYER_HAS_WON, ap.getName()),
                             "END");
 
-                    ArenaModuleManager.announce(arena,
-                            Language.parse(arena, MSG.PLAYER_HAS_WON, ap.getName()),
+                    ArenaModuleManager.announce(this.arena,
+                            Language.parse(this.arena, MSG.PLAYER_HAS_WON, ap.getName()),
                             "WINNER");
 
-                    arena.broadcast(Language.parse(arena, MSG.PLAYER_HAS_WON,
+                    this.arena.broadcast(Language.parse(this.arena, MSG.PLAYER_HAS_WON,
                             ap.getName()));
                 } else {
                     ArenaModuleManager.announce(
-                            arena,
-                            Language.parse(arena, MSG.TEAM_HAS_WON,
+                            this.arena,
+                            Language.parse(this.arena, MSG.TEAM_HAS_WON,
                                     team.getColoredName()), "END");
 
                     ArenaModuleManager.announce(
-                            arena,
-                            Language.parse(arena, MSG.TEAM_HAS_WON,
+                            this.arena,
+                            Language.parse(this.arena, MSG.TEAM_HAS_WON,
                                     team.getColoredName()), "WINNER");
 
-                    arena.broadcast(Language.parse(arena, MSG.TEAM_HAS_WON,
+                    this.arena.broadcast(Language.parse(this.arena, MSG.TEAM_HAS_WON,
                             team.getColoredName()));
                     break;
                 }
             }
 
-            if (ArenaModuleManager.commitEnd(arena, team)) {
+            if (ArenaModuleManager.commitEnd(this.arena, team)) {
                 return;
             }
         }
-        endRunner = new EndRunnable(arena, arena.getArenaConfig().getInt(
+        this.endRunner = new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
 
     @Override
     public void parsePlayerDeath(final Player player, final EntityDamageEvent event) {
-        if (!getLifeMap().containsKey(player.getName())) {
+        if (!this.getLifeMap().containsKey(player.getName())) {
             return;
         }
-        if (arena.getArenaConfig().getBoolean(CFG.GOAL_PLAYERKILLREWARD_GRADUALLYDOWN)) {
-            int lives = getLifeMap().get(player.getName());
-            lives++;
-            getLifeMap().put(player.getName(), lives);
-        } else {
-            getLifeMap().put(player.getName(), getMaxInt());
+        if (!this.arena.getArenaConfig().getBoolean(CFG.GOAL_PLAYERKILLREWARD_GRADUALLYDOWN)) {
+            this.getLifeMap().put(player.getName(), this.getDefaultRemainingKills());
         }
 
 
@@ -280,7 +276,7 @@ class ResetRunnable implements Runnable {
 
             @Override
             public void run() {
-                reset(player);
+                this.reset(this.player);
             }
 
             ResetRunnable(final Player player) {
@@ -288,19 +284,19 @@ public void run() {
             }
 
             private void reset(final Player player) {
-                if (!getLifeMap().containsKey(player.getName())) {
+                if (!GoalPlayerKillReward.this.getLifeMap().containsKey(player.getName())) {
                     return;
                 }
 
-                final int iLives = getLifeMap().get(player.getName());
+                final int iLives = GoalPlayerKillReward.this.getLifeMap().get(player.getName());
                 if (ArenaPlayer.parsePlayer(player.getName()).getStatus() != Status.FIGHT) {
                     return;
                 }
-                if (!arena.getArenaConfig().getBoolean(CFG.GOAL_PLAYERKILLREWARD_ONLYGIVE)) {
+                if (!GoalPlayerKillReward.this.arena.getArenaConfig().getBoolean(CFG.GOAL_PLAYERKILLREWARD_ONLYGIVE)) {
                     InventoryManager.clearInventory(player);
                 }
-                if (getItemMap().containsKey(iLives)) {
-                    ArenaClass.equip(player, getItemMap().get(iLives));
+                if (GoalPlayerKillReward.this.getItemMap().containsKey(iLives)) {
+                    ArenaClass.equip(player, GoalPlayerKillReward.this.getItemMap().get(iLives));
                 } else {
                     ArenaPlayer.parsePlayer(player.getName()).getArenaClass()
                             .equip(player);
@@ -316,21 +312,21 @@ private void reset(final Player player) {
             return;
         }
 
-        int iLives = getLifeMap().get(killer.getName());
-        arena.getDebugger().i("kills to go for " + killer.getName() + ": " + iLives, killer);
+        int iLives = this.getLifeMap().get(killer.getName());
+        this.arena.getDebugger().i("kills to go for " + killer.getName() + ": " + iLives, killer);
         if (iLives <= 1) {
             // player has won!
-            final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "trigger:" + killer.getName(), "playerKill:" + killer.getName() + ':' + player.getName(), "playerDeath:" + player.getName());
+            final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "trigger:" + killer.getName(), "playerKill:" + killer.getName() + ':' + player.getName(), "playerDeath:" + player.getName());
             Bukkit.getPluginManager().callEvent(gEvent);
             final Set plrs = new HashSet<>();
-            for (final ArenaPlayer ap : arena.getFighters()) {
+            for (final ArenaPlayer ap : this.arena.getFighters()) {
                 if (ap.getName().equals(killer.getName())) {
                     continue;
                 }
                 plrs.add(ap);
             }
             for (final ArenaPlayer ap : plrs) {
-                getLifeMap().remove(ap.getName());
+                this.getLifeMap().remove(ap.getName());
 				/*
 				arena.getDebugger().i("faking player death", ap.get());
 				arena.removePlayer(ap.get(), CFG.TP_LOSE.toString(), true,
@@ -342,41 +338,33 @@ private void reset(final Player player) {
                 //PlayerState.fullReset(arena, ap.get());
             }
 
-            if (ArenaManager.checkAndCommit(arena, false)) {
+            if (ArenaManager.checkAndCommit(this.arena, false)) {
                 return;
             }
-            PACheck.handleEnd(arena, false);
+            PACheck.handleEnd(this.arena, false);
         } else {
-            final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "playerKill:" + killer.getName() + ':' + player.getName(), "playerDeath:" + player.getName());
+            final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "playerKill:" + killer.getName() + ':' + player.getName(), "playerDeath:" + player.getName());
             Bukkit.getPluginManager().callEvent(gEvent);
             iLives--;
-            getLifeMap().put(killer.getName(), iLives);
+            this.getLifeMap().put(killer.getName(), iLives);
             Bukkit.getScheduler().runTaskLater(PVPArena.instance,
                     new ResetRunnable(killer), 4L);
         }
     }
 
-    @Override
-    public void displayInfo(final CommandSender sender) {
-        for (final int i : getItemMap().keySet()) {
-            final ItemStack[] items = getItemMap().get(i);
-            sender.sendMessage("kill #" + i + ": " + StringParser.getStringFromItemStacks(items));
-        }
-    }
-
-    private Map getItemMap() {
-        if (itemMap == null) {
-            itemMap = new HashMap<>();
+    private Map getItemMap() {
+        if (this.itemMapCubed == null) {
+            this.itemMapCubed = new HashMap<>();
         }
-        return itemMap;
+        return this.itemMapCubed;
     }
 
     @Override
     public boolean hasSpawn(final String string) {
-        if (arena.isFreeForAll()) {
+        if (this.arena.isFreeForAll()) {
 
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -385,14 +373,14 @@ public boolean hasSpawn(final String string) {
             }
             return string.toLowerCase().startsWith("spawn");
         }
-        for (final String teamName : arena.getTeamNames()) {
+        for (final String teamName : this.arena.getTeamNames()) {
             if (string.toLowerCase().startsWith(
                     teamName.toLowerCase() + "spawn")) {
                 return true;
             }
 
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(teamName.toLowerCase() +
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -405,12 +393,12 @@ public boolean hasSpawn(final String string) {
 
     @Override
     public void initate(final Player player) {
-        getLifeMap().put(player.getName(), getMaxInt());
+        this.getLifeMap().put(player.getName(), this.getDefaultRemainingKills());
     }
 
-    private int getMaxInt() {
+    private int getDefaultRemainingKills() {
         int max = 0;
-        for (final int i : getItemMap().keySet()) {
+        for (final int i : this.getItemMap().keySet()) {
             max = Math.max(max, i);
         }
         return max + 1;
@@ -425,43 +413,41 @@ public boolean isInternal() {
     public void parseLeave(final Player player) {
         if (player == null) {
             PVPArena.instance.getLogger().warning(
-                    getName() + ": player NULL");
+                    this.getName() + ": player NULL");
             return;
         }
-        if (getLifeMap().containsKey(player.getName())) {
-            getLifeMap().remove(player.getName());
-        }
+        this.getLifeMap().remove(player.getName());
     }
 
     @Override
     public void parseStart() {
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
-                getLifeMap().put(ap.getName(), getMaxInt());
+                this.getLifeMap().put(ap.getName(), this.getDefaultRemainingKills());
             }
         }
     }
 
     @Override
     public void reset(final boolean force) {
-        endRunner = null;
-        getLifeMap().clear();
+        this.endRunner = null;
+        this.getLifeMap().clear();
     }
 
     @Override
     public void setDefaults(final YamlConfiguration config) {
-        if (!arena.isFreeForAll()) {
+        if (!this.arena.isFreeForAll()) {
             if (config.get("teams.free") != null) {
                 config.set("teams", null);
             }
             if (config.get("teams") == null) {
-                arena.getDebugger().i("no teams defined, adding custom red and blue!");
+                this.arena.getDebugger().i("no teams defined, adding custom red and blue!");
                 config.addDefault("teams.red", ChatColor.RED.name());
                 config.addDefault("teams.blue", ChatColor.BLUE.name());
             }
-            if (arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)
+            if (this.arena.getArenaConfig().getBoolean(CFG.GOAL_FLAGS_WOOLFLAGHEAD)
                     && config.get("flagColors") == null) {
-                arena.getDebugger().i("no flagheads defined, adding white and black!");
+                this.arena.getDebugger().i("no flagheads defined, adding white and black!");
                 config.addDefault("flagColors.red", "WHITE");
                 config.addDefault("flagColors.blue", "BLACK");
             }
@@ -474,45 +460,91 @@ public void setDefaults(final YamlConfiguration config) {
         if (cs != null) {
             for (final String line : cs.getKeys(false)) {
                 try {
-                    getItemMap().put(Integer.parseInt(line.substring(2)), StringParser
-                            .getItemStacksFromString(cs.getString(line)));
-                } catch (final Exception e) {
+                    this.getItemMap().put(Integer.parseInt(line.substring(2)),
+                        new ItemStack[][] {
+                            cs.getList(line + ".items").toArray(new ItemStack[0]),
+                            cs.getList(line + ".offhand").toArray(new ItemStack[]{new ItemStack(Material.AIR, 1)}),
+                            cs.getList(line + ".armor").toArray(new ItemStack[0])
+                        });
+                } catch (final Exception ignored) {
                 }
             }
         }
 
-        if (getItemMap().size() < 1) {
-
-            getItemMap().put(5,
-                    StringParser.getItemStacksFromString("298,299,300,301,268")); // leather
-            getItemMap().put(4,
-                    StringParser.getItemStacksFromString("302,303,304,305,272")); // chain
-            getItemMap().put(3,
-                    StringParser.getItemStacksFromString("314,315,316,317,267")); // gold
-            getItemMap().put(2,
-                    StringParser.getItemStacksFromString("306,307,308,309,276")); // iron
-            getItemMap().put(1,
-                    StringParser.getItemStacksFromString("310,311,312,313,276")); // diamond
-
-            saveItems();
+        if (this.getItemMap().size() < 1) {
+
+            this.getItemMap().put(5, new ItemStack[][]{
+                        new ItemStack[]{new ItemStack(Material.WOODEN_SWORD, 1)},
+                        new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                        new ItemStack[]{
+                                new ItemStack(Material.LEATHER_HELMET, 1),
+                                new ItemStack(Material.LEATHER_CHESTPLATE, 1),
+                                new ItemStack(Material.LEATHER_LEGGINGS, 1),
+                                new ItemStack(Material.LEATHER_BOOTS, 1),
+                        },
+                    });
+            this.getItemMap().put(4, new ItemStack[][]{
+                    new ItemStack[]{new ItemStack(Material.STONE_SWORD, 1)},
+                    new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                    new ItemStack[]{
+                            new ItemStack(Material.CHAINMAIL_HELMET, 1),
+                            new ItemStack(Material.CHAINMAIL_CHESTPLATE, 1),
+                            new ItemStack(Material.CHAINMAIL_LEGGINGS, 1),
+                            new ItemStack(Material.CHAINMAIL_BOOTS, 1),
+                    },
+            });
+            this.getItemMap().put(3, new ItemStack[][]{
+                    new ItemStack[]{new ItemStack(Material.IRON_SWORD, 1)},
+                    new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                    new ItemStack[]{
+                            new ItemStack(Material.GOLDEN_HELMET, 1),
+                            new ItemStack(Material.GOLDEN_CHESTPLATE, 1),
+                            new ItemStack(Material.GOLDEN_LEGGINGS, 1),
+                            new ItemStack(Material.GOLDEN_BOOTS, 1),
+                    },
+            });
+            this.getItemMap().put(2, new ItemStack[][]{
+                    new ItemStack[]{new ItemStack(Material.DIAMOND_SWORD, 1)},
+                    new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                    new ItemStack[]{
+                            new ItemStack(Material.IRON_HELMET, 1),
+                            new ItemStack(Material.IRON_CHESTPLATE, 1),
+                            new ItemStack(Material.IRON_LEGGINGS, 1),
+                            new ItemStack(Material.IRON_BOOTS, 1),
+                    },
+            });
+            this.getItemMap().put(1, new ItemStack[][]{
+                    new ItemStack[]{new ItemStack(Material.DIAMOND_SWORD, 1)},
+                    new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                    new ItemStack[]{
+                            new ItemStack(Material.DIAMOND_HELMET, 1),
+                            new ItemStack(Material.DIAMOND_CHESTPLATE, 1),
+                            new ItemStack(Material.DIAMOND_LEGGINGS, 1),
+                            new ItemStack(Material.DIAMOND_BOOTS, 1),
+                    },
+            });
+
+            this.saveItems();
         }
     }
 
     private void saveItems() {
-        for (final int i : getItemMap().keySet()) {
-            arena.getArenaConfig().setManually("goal.playerkillrewards.kr" + i,
-                    StringParser.getStringFromItemStacks(getItemMap().get(i)));
-        }
-        arena.getArenaConfig().save();
+        for (final int i : this.getItemMap().keySet()) {
+            this.arena.getArenaConfig().setManually("goal.playerkillrewards.kr" + i+".items",
+                    getSerializableItemStacks(this.getItemMap().get(i)[0]));
+            this.arena.getArenaConfig().setManually("goal.playerkillrewards.kr" + i+".offhand",
+                    getSerializableItemStacks(this.getItemMap().get(i)[1]));
+            this.arena.getArenaConfig().setManually("goal.playerkillrewards.kr" + i+".armor",
+                    getSerializableItemStacks(this.getItemMap().get(i)[2]));
+        }
+        this.arena.getArenaConfig().save();
     }
 
     @Override
     public Map timedEnd(final Map scores) {
 
-        for (final ArenaPlayer ap : arena.getFighters()) {
-            double score = getMaxInt()
-                    - (getLifeMap().containsKey(ap.getName()) ? getLifeMap()
-                    .get(ap.getName()) : 0);
+        for (final ArenaPlayer ap : this.arena.getFighters()) {
+            double score = this.getDefaultRemainingKills() - (this.getLifeMap().getOrDefault(ap.getName(), 0));
             if (scores.containsKey(ap.getName())) {
                 scores.put(ap.getName(), scores.get(ap.getName()) + score);
             } else {
@@ -523,8 +555,35 @@ public Map timedEnd(final Map scores) {
         return scores;
     }
 
+    @Override
+    public PACheck getLives(PACheck res, ArenaPlayer player) {
+        if (res.getPriority() <= PRIORITY + 1000) {
+            if (this.arena.isFreeForAll()) {
+                res.setError(
+                        this, String.valueOf(this.getLifeMap().getOrDefault(player.getName(), 0))
+                );
+            } else {
+                if (this.getLifeMap().containsKey(player.getArenaTeam().getName())) {
+                    res.setError(this, String.valueOf(this.getLifeMap().get(player.getName())));
+                } else {
+
+                    int sum = 0;
+
+                    for (final ArenaPlayer ap : player.getArenaTeam().getTeamMembers()) {
+                        if (this.getLifeMap().containsKey(ap.getName())) {
+                            sum += this.getLifeMap().get(ap.getName());
+                        }
+                    }
+
+                    res.setError(this, String.valueOf(sum));
+                }
+            }
+        }
+        return res;
+    }
+
     @Override
     public void unload(final Player player) {
-        getLifeMap().remove(player.getName());
+        this.getLifeMap().remove(player.getName());
     }
 }
diff --git a/src/net/slipcor/pvparena/goals/GoalPlayerLives.java b/src/net/slipcor/pvparena/goals/GoalPlayerLives.java
index ea5717f57..051685c80 100644
--- a/src/net/slipcor/pvparena/goals/GoalPlayerLives.java
+++ b/src/net/slipcor/pvparena/goals/GoalPlayerLives.java
@@ -226,30 +226,17 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             pos--;
             getLifeMap().put(player.getName(), pos);
 
-            final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
-                    .getArenaTeam();
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                if (arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY_REMAINING,
-                            respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                            arena.parseDeathCause(player, event.getEntity()
-                                            .getLastDamageCause().getCause(),
-                                    player.getKiller()), String.valueOf(pos)));
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
+                    this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING, player, event, pos);
                 } else {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                            arena.parseDeathCause(player, event.getEntity()
-                                            .getLastDamageCause().getCause(),
-                                    player.getKiller())));
+                    this.broadcastSimpleDeathMessage(player, event);
                 }
-
             }
+
             final List returned;
 
-            if (arena.getArenaConfig().getBoolean(
-                    CFG.PLAYER_DROPSINVENTORY)) {
+            if (arena.getArenaConfig().getBoolean(CFG.PLAYER_DROPSINVENTORY)) {
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
@@ -257,8 +244,7 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
                 returned.addAll(event.getDrops());
             }
 
-            PACheck.handleRespawn(arena,
-                    ArenaPlayer.parsePlayer(player.getName()), returned);
+            PACheck.handleRespawn(arena, ArenaPlayer.parsePlayer(player.getName()), returned);
 
         }
     }
@@ -276,8 +262,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
             if (arena.isFreeForAll()) {
                 res.setError(
                         this,
-                        String.valueOf(getLifeMap().containsKey(aPlayer.getName()) ? getLifeMap().get(aPlayer
-                                .getName()) : 0));
+                        String.valueOf(getLifeMap().getOrDefault(aPlayer.getName(), 0))
+                );
             } else {
 
                 if (getLifeMap().containsKey(aPlayer.getArenaTeam().getName())) {
diff --git a/src/net/slipcor/pvparena/goals/GoalSabotage.java b/src/net/slipcor/pvparena/goals/GoalSabotage.java
index e4a5b5797..8a6d71b59 100644
--- a/src/net/slipcor/pvparena/goals/GoalSabotage.java
+++ b/src/net/slipcor/pvparena/goals/GoalSabotage.java
@@ -17,11 +17,9 @@
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
 import net.slipcor.pvparena.managers.SpawnManager;
-import net.slipcor.pvparena.managers.StatisticsManager.type;
+import net.slipcor.pvparena.managers.StatisticsManager.Type;
 import net.slipcor.pvparena.runnables.EndRunnable;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
+import org.bukkit.*;
 import org.bukkit.block.Block;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
@@ -89,7 +87,7 @@ public PACheck checkCommand(final PACheck res, final String string) {
 
     @Override
     public List getMain() {
-        final List result = Arrays.asList(new String[0]);
+        final List result = new ArrayList<>();
         if (arena != null) {
             for (final ArenaTeam team : arena.getTeams()) {
                 final String sTeam = team.getName();
@@ -121,66 +119,100 @@ public PACheck checkInteract(final PACheck res, final Player player, final Block
         if (block == null || res.getPriority() > PRIORITY) {
             return res;
         }
-        arena.getDebugger().i("checking interact", player);
+        this.arena.getDebugger().i("checking interact", player);
 
         if (block.getType() != Material.TNT) {
-            arena.getDebugger().i("block, but not flag", player);
+            this.arena.getDebugger().i("block, but not flag", player);
             return res;
         }
-        arena.getDebugger().i("flag click!", player);
-
-        if (player.getEquipment().getItemInMainHand() == null
-                || player.getEquipment().getItemInMainHand().getType() != Material.FLINT_AND_STEEL) {
-            arena.getDebugger().i("block, but no sabotage items", player);
-            return res;
-        }
-
+        this.arena.getDebugger().i("tnt clicked. Checking if it's a flag", player);
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
-
         final ArenaTeam pTeam = aPlayer.getArenaTeam();
+
         if (pTeam == null) {
+            this.arena.getDebugger().i("Player is not in team. Cancelled", player);
             return res;
         }
+
         Vector vFlag = null;
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             final String aTeam = team.getName();
-            if (team.getTeamMembers().size() < 1) {
+            if (team.getTeamMembers().isEmpty()) {
                 continue; // dont check for inactive teams
             }
-            arena.getDebugger().i("checking for tnt of team " + aTeam, player);
+            this.arena.getDebugger().i("checking for tnt of team " + aTeam, player);
             Vector vLoc = block.getLocation().toVector();
-            arena.getDebugger().i("block: " + vLoc, player);
-            if (!SpawnManager.getBlocksStartingWith(arena, aTeam + "tnt").isEmpty()) {
+            this.arena.getDebugger().i("block: " + vLoc, player);
+            if (!SpawnManager.getBlocksStartingWith(this.arena, aTeam + "tnt").isEmpty()) {
+                vFlag = SpawnManager
+                        .getBlockNearest(
+                                SpawnManager.getBlocksStartingWith(this.arena, aTeam + "tnt"),
+                                new PABlockLocation(player.getLocation()))
+                        .toLocation().toVector();
+            }
+
+            if (vFlag != null && vLoc.distance(vFlag) < 2) {
+                this.arena.getDebugger().i("flag found!", player);
+                this.arena.getDebugger().i("vFlag: " + vFlag, player);
+
+                res.setPriority(this, PRIORITY);
+            }
+        }
+        return res;
+    }
+
+    @Override
+    public void commitInteract(final Player player, final Block clickedBlock) {
+        final ArenaPlayer arenaPlayer = ArenaPlayer.parsePlayer(player.getName());
+        final ArenaTeam playerTeam = arenaPlayer.getArenaTeam();
+
+        if (player.getEquipment().getItemInMainHand().getType() == Material.AIR
+                || player.getEquipment().getItemInMainHand().getType() != Material.FLINT_AND_STEEL) {
+            this.arena.getDebugger().i("block, but no sabotage items", player);
+            this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_SABOTAGE_NOTGOODITEM));
+            return;
+        }
+
+        Vector vFlag = null;
+        for (final ArenaTeam team : this.arena.getTeams()) {
+            final String aTeam = team.getName();
+            if (team.getTeamMembers().isEmpty()) {
+                continue; // dont check for inactive teams
+            }
+            this.arena.getDebugger().i("checking for tnt of team " + aTeam, player);
+            Vector vLoc = clickedBlock.getLocation().toVector();
+            this.arena.getDebugger().i("block: " + vLoc, player);
+            if (!SpawnManager.getBlocksStartingWith(this.arena, aTeam + "tnt").isEmpty()) {
                 vFlag = SpawnManager
                         .getBlockNearest(
-                                SpawnManager.getBlocksStartingWith(arena, aTeam + "tnt"),
+                                SpawnManager.getBlocksStartingWith(this.arena, aTeam + "tnt"),
                                 new PABlockLocation(player.getLocation()))
                         .toLocation().toVector();
             }
 
             if (vFlag != null && vLoc.distance(vFlag) < 2) {
-                arena.getDebugger().i("flag found!", player);
-                arena.getDebugger().i("vFlag: " + vFlag, player);
+                this.arena.getDebugger().i("flag found!", player);
+                this.arena.getDebugger().i("vFlag: " + vFlag, player);
+
+                this.arena.getDebugger().i("aTeam: " + aTeam + " pTeam: " + playerTeam);
 
-                if (aTeam.equals(pTeam.getName())) {
-                    res.setError(this, Language.parse(MSG.GOAL_SABOTAGE_YOUCANNOTSELFDESTROY));
+                if (aTeam.equals(playerTeam.getName())) {
+                    this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_SABOTAGE_NOSELFDESTROY));
                     continue;
                 }
 
-                arena.broadcast(Language.parse(arena, MSG.GOAL_SABOTAGE_IGNITED,
-                        pTeam.colorizePlayer(player) + ChatColor.YELLOW,
+                this.arena.broadcast(Language.parse(this.arena, MSG.GOAL_SABOTAGE_IGNITED,
+                        playerTeam.colorizePlayer(player) + ChatColor.YELLOW,
                         team.getColoredName() + ChatColor.YELLOW));
 
-                final PAGoalEvent gEvent = new PAGoalEvent(arena, this, "trigger:" + player.getName());
+                final PAGoalEvent gEvent = new PAGoalEvent(this.arena, this, "trigger:" + player.getName());
                 Bukkit.getPluginManager().callEvent(gEvent);
                 takeFlag(team.getName(), true,
-                        new PABlockLocation(block.getLocation()));
-                res.setPriority(this, PRIORITY);
-                return res;
+                        new PABlockLocation(clickedBlock.getLocation()));
+
+                break;
             }
         }
-
-        return res;
     }
 
     @Override
@@ -189,12 +221,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        final int maxPlayers = arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
-        final int maxTeamPlayers = arena.getArenaConfig().getInt(
+        final int maxPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MAXPLAYERS);
+        final int maxTeamPlayers = this.arena.getArenaConfig().getInt(
                 CFG.READY_MAXTEAMPLAYERS);
 
-        if (maxPlayers > 0 && arena.getFighters().size() >= maxPlayers) {
-            res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_ARENA_FULL));
+        if (maxPlayers > 0 && this.arena.getFighters().size() >= maxPlayers) {
+            res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_ARENA_FULL));
             return res;
         }
 
@@ -202,12 +234,12 @@ public PACheck checkJoin(final CommandSender sender, final PACheck res, final St
             return res;
         }
 
-        if (!arena.isFreeForAll()) {
-            final ArenaTeam team = arena.getTeam(args[0]);
+        if (!this.arena.isFreeForAll()) {
+            final ArenaTeam team = this.arena.getTeam(args[0]);
 
             if (team != null && maxTeamPlayers > 0
                     && team.getTeamMembers().size() >= maxTeamPlayers) {
-                res.setError(this, Language.parse(arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
+                res.setError(this, Language.parse(this.arena, MSG.ERROR_JOIN_TEAM_FULL, team.getName()));
                 return res;
             }
         }
@@ -228,7 +260,7 @@ public PACheck checkSetBlock(final PACheck res, final Player player, final Block
         }
 
         if (!PVPArena.hasAdminPerms(player)
-                && !PVPArena.hasCreatePerms(player, arena)) {
+                && !PVPArena.hasCreatePerms(player, this.arena)) {
             return res;
         }
         res.setPriority(this, PRIORITY); // success :)
@@ -254,7 +286,7 @@ private void commit(final Arena arena, final String sTeam) {
             }
             for (final ArenaPlayer ap : team.getTeamMembers()) {
 
-                ap.addStatistic(arena.getName(), type.LOSSES, 1);
+                ap.addStatistic(arena.getName(), Type.LOSSES, 1);
                 /*
 				arena.tpPlayerToCoordName(ap.get(), "spectator");
 				ap.setTelePass(false);*/
@@ -263,12 +295,8 @@ private void commit(final Arena arena, final String sTeam) {
             }
         }
         for (final ArenaTeam team : arena.getTeams()) {
-            for (final ArenaPlayer ap : team.getTeamMembers()) {
-                if (ap.getStatus() != Status.FIGHT) {
-                    continue;
-                }
+            if (team.getTeamMembers().stream().anyMatch(ap -> ap.getStatus() == Status.FIGHT)) {
                 winteam = team.getName();
-                break;
             }
         }
 
@@ -293,14 +321,14 @@ private void commit(final Arena arena, final String sTeam) {
     @Override
     public void commitCommand(final CommandSender sender, final String[] args) {
         if (args[0].contains("tnt")) {
-            for (final ArenaTeam team : arena.getTeams()) {
+            for (final ArenaTeam team : this.arena.getTeams()) {
                 final String sTeam = team.getName();
                 if (args[0].contains(sTeam + "tnt")) {
-                    flagName = args[0];
-                    PAA_Region.activeSelections.put(sender.getName(), arena);
+                    this.flagName = args[0];
+                    PAA_Region.activeSelections.put(sender.getName(), this.arena);
 
-                    arena.msg(sender, Language.parse(arena,
-                            MSG.GOAL_SABOTAGE_TOSETTNT, flagName));
+                    this.arena.msg(sender, Language.parse(this.arena,
+                            MSG.GOAL_SABOTAGE_TOSETTNT, this.flagName));
                 }
             }
         }
@@ -308,15 +336,15 @@ public void commitCommand(final CommandSender sender, final String[] args) {
 
     @Override
     public void commitEnd(final boolean force) {
-        if (arena.realEndRunner != null) {
-            arena.getDebugger().i("[SABOTAGE] already ending");
+        if (this.arena.realEndRunner != null) {
+            this.arena.getDebugger().i("[SABOTAGE] already ending");
             return;
         }
-        arena.getDebugger().i("[SABOTAGE]");
+        this.arena.getDebugger().i("[SABOTAGE]");
 
         ArenaTeam aTeam = null;
 
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             for (final ArenaPlayer ap : team.getTeamMembers()) {
                 if (ap.getStatus() == Status.FIGHT) {
                     aTeam = team;
@@ -327,43 +355,39 @@ public void commitEnd(final boolean force) {
 
         if (aTeam != null && !force) {
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "END");
             ArenaModuleManager.announce(
-                    arena,
-                    Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+                    this.arena,
+                    Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                             + aTeam.getName() + ChatColor.YELLOW), "WINNER");
-            arena.broadcast(Language.parse(arena, MSG.TEAM_HAS_WON, aTeam.getColor()
+            this.arena.broadcast(Language.parse(this.arena, MSG.TEAM_HAS_WON, aTeam.getColor()
                     + aTeam.getName() + ChatColor.YELLOW));
         }
 
-        if (ArenaModuleManager.commitEnd(arena, aTeam)) {
+        if (ArenaModuleManager.commitEnd(this.arena, aTeam)) {
             return;
         }
-        new EndRunnable(arena, arena.getArenaConfig().getInt(
+        new EndRunnable(this.arena, this.arena.getArenaConfig().getInt(
                 CFG.TIME_ENDCOUNTDOWN));
     }
 
-    @Override
-    public void commitInteract(final Player player, final Block clickedBlock) {
-    }
-
     @Override
     public boolean commitSetFlag(final Player player, final Block block) {
 
-        arena.getDebugger().i("trying to set a tnt", player);
+        this.arena.getDebugger().i("trying to set a tnt", player);
 
         // command : /pa redtnt1
         // location: red1tnt:
 
-        SpawnManager.setBlock(arena, new PABlockLocation(block.getLocation()),
-                flagName);
+        SpawnManager.setBlock(this.arena, new PABlockLocation(block.getLocation()),
+                this.flagName);
 
-        arena.msg(player, Language.parse(arena, MSG.GOAL_SABOTAGE_SETTNT, flagName));
+        this.arena.msg(player, Language.parse(this.arena, MSG.GOAL_SABOTAGE_SETTNT, this.flagName));
 
         PAA_Region.activeSelections.remove(player.getName());
-        flagName = "";
+        this.flagName = "";
         return true;
     }
 
@@ -377,7 +401,7 @@ public void disconnect(final ArenaPlayer aPlayer) {
 
         final String flag = getHeldFlagTeam(aPlayer.getName());
         if (flag != null) {
-            final ArenaTeam flagTeam = arena.getTeam(flag);
+            final ArenaTeam flagTeam = this.arena.getTeam(flag);
             getFlagMap().remove(flag);
             distributeFlag(aPlayer, flagTeam);
         }
@@ -389,7 +413,7 @@ private void distributeFlag(final ArenaPlayer player, final ArenaTeam team) {
         int pos = new Random().nextInt(players.size());
 
         for (final ArenaPlayer ap : players) {
-            arena.getDebugger().i("distributing sabotage: " + ap.getName(), ap.getName());
+            this.arena.getDebugger().i("distributing sabotage: " + ap.getName(), ap.getName());
             if (ap.equals(player)) {
                 continue;
             }
@@ -397,7 +421,7 @@ private void distributeFlag(final ArenaPlayer player, final ArenaTeam team) {
                 getFlagMap().put(team.getName(), ap.getName());
                 ap.get().getInventory()
                         .addItem(new ItemStack(Material.FLINT_AND_STEEL, 1));
-                arena.msg(ap.get(), Language.parse(arena, MSG.GOAL_SABOTAGE_YOUTNT));
+                this.arena.msg(ap.get(), Language.parse(this.arena, MSG.GOAL_SABOTAGE_YOUTNT));
                 return;
             }
         }
@@ -408,9 +432,9 @@ private String getHeldFlagTeam(final String player) {
             return null;
         }
 
-        arena.getDebugger().i("getting held TNT of player " + player, player);
+        this.arena.getDebugger().i("getting held TNT of player " + player, player);
         for (final String sTeam : getFlagMap().keySet()) {
-            arena.getDebugger().i("team " + sTeam + "'s sabotage is carried by "
+            this.arena.getDebugger().i("team " + sTeam + "'s sabotage is carried by "
                     + getFlagMap().get(sTeam) + "s hands", player);
             if (player.equals(getFlagMap().get(sTeam))) {
                 return sTeam;
@@ -420,31 +444,31 @@ private String getHeldFlagTeam(final String player) {
     }
 
     private Map getFlagMap() {
-        if (teamFlags == null) {
-            teamFlags = new HashMap<>();
+        if (this.teamFlags == null) {
+            this.teamFlags = new HashMap<>();
         }
-        return teamFlags;
+        return this.teamFlags;
     }
 
     private Map getTNTmap() {
-        if (teamTNTs == null) {
-            teamTNTs = new HashMap<>();
+        if (this.teamTNTs == null) {
+            this.teamTNTs = new HashMap<>();
         }
-        return teamTNTs;
+        return this.teamTNTs;
     }
 
     @Override
     public boolean hasSpawn(final String string) {
-        for (final String teamName : arena.getTeamNames()) {
-            if (string.toLowerCase().equals(teamName.toLowerCase() + "tnt")) {
+        for (final String teamName : this.arena.getTeamNames()) {
+            if (string.equalsIgnoreCase(teamName + "tnt")) {
                 return true;
             }
             if (string.toLowerCase().startsWith(
                     teamName.toLowerCase() + "spawn")) {
                 return true;
             }
-            if (arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
-                for (final ArenaClass aClass : arena.getClasses()) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_CLASSSPAWN)) {
+                for (final ArenaClass aClass : this.arena.getClasses()) {
                     if (string.toLowerCase().startsWith(teamName.toLowerCase() +
                             aClass.getName().toLowerCase() + "spawn")) {
                         return true;
@@ -460,10 +484,10 @@ public void initate(final Player player) {
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
         final ArenaTeam team = aPlayer.getArenaTeam();
         takeFlag(team.getName(), false,
-                SpawnManager.getBlockByExactName(arena, team.getName() + "tnt"));
+                SpawnManager.getBlockByExactName(this.arena, team.getName() + "tnt"));
         //TODO: allow multiple TNTs?
         if (!getFlagMap().containsKey(team.getName())) {
-            arena.getDebugger().i("adding team " + team.getName(), player);
+            this.arena.getDebugger().i("adding team " + team.getName(), player);
             distributeFlag(null, team);
         }
     }
@@ -476,7 +500,7 @@ public boolean isInternal() {
     @Override
     public void parsePlayerDeath(final Player player, final EntityDamageEvent event) {
         final String teamName = getHeldFlagTeam(player.getName());
-        final ArenaTeam team = arena.getTeam(teamName);
+        final ArenaTeam team = this.arena.getTeam(teamName);
         if (teamName != null && team != null) {
             final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
             getFlagMap().remove(teamName);
@@ -486,14 +510,14 @@ public void parsePlayerDeath(final Player player, final EntityDamageEvent event)
 
     @Override
     public void parseStart() {
-        arena.getDebugger().i("initiating arena");
+        this.arena.getDebugger().i("initiating arena");
         getFlagMap().clear();
-        for (final ArenaTeam team : arena.getTeams()) {
+        for (final ArenaTeam team : this.arena.getTeams()) {
             takeFlag(team.getName(), false,
-                    SpawnManager.getBlockByExactName(arena, team.getName() + "tnt"));
+                    SpawnManager.getBlockByExactName(this.arena, team.getName() + "tnt"));
             // TODO: allow multiple TNTs?
             if (!getFlagMap().containsKey(team.getName())) {
-                arena.getDebugger().i("adding team " + team.getName());
+                this.arena.getDebugger().i("adding team " + team.getName());
                 distributeFlag(null, team);
             }
         }
@@ -510,14 +534,14 @@ public void reset(final boolean force) {
 
     @Override
     public void setDefaults(final YamlConfiguration config) {
-        if (arena.isFreeForAll()) {
+        if (this.arena.isFreeForAll()) {
             return;
         }
         if (config.get("teams.free") != null) {
             config.set("teams", null);
         }
         if (config.get("teams") == null) {
-            arena.getDebugger().i("no teams defined, adding custom red and blue!");
+            this.arena.getDebugger().i("no teams defined, adding custom red and blue!");
             config.addDefault("teams.red", ChatColor.RED.name());
             config.addDefault("teams.blue", ChatColor.BLUE.name());
         }
@@ -531,13 +555,15 @@ public void setDefaults(final YamlConfiguration config) {
      * @param paBlockLocation the location to take/reset
      */
     void takeFlag(final String teamName, final boolean take, final PABlockLocation paBlockLocation) {
+        this.arena.getDebugger().i(String.format("Take flag for team %s, take: %s, location: %s", teamName, take, paBlockLocation.toString()));
         paBlockLocation.toLocation().getBlock()
                 .setType(take ? Material.AIR : Material.TNT);
         if (take) {
             final TNTPrimed tnt = (TNTPrimed) Bukkit.getWorld(
                     paBlockLocation.getWorldName())
                     .spawnEntity(paBlockLocation.toLocation(), EntityType.PRIMED_TNT);
-            getTNTmap().put(arena.getTeam(teamName), tnt);
+
+            getTNTmap().put(this.arena.getTeam(teamName), tnt);
         }
     }
 
@@ -555,24 +581,19 @@ public void onTNTExplode(final EntityExplodeEvent event) {
         final TNTPrimed tnt = (TNTPrimed) event.getEntity();
 
         for (final ArenaTeam team : getTNTmap().keySet()) {
+            this.arena.getDebugger().i(String.format("Checking tnt %s for team %s", tnt.getUniqueId(), team.getName()));
             if (tnt.getUniqueId().equals(getTNTmap().get(team).getUniqueId())) {
                 event.setCancelled(true);
-                tnt.remove();
-                commit(arena, team.getName());
-            }
-        }
-
-        final PABlockLocation tLoc = new PABlockLocation(event.getEntity()
-                .getLocation());
-
-        for (final String sTeam : arena.getTeamNames()) {
-            final Set locs = SpawnManager.getBlocksStartingWith(arena, sTeam + "tnt");
-
-            final PABlockLocation nearest = SpawnManager.getBlockNearest(locs, tLoc);
 
-            if (nearest.getDistanceSquared(tLoc) < 4) {
-                event.setCancelled(true);
-                return;
+                commit(this.arena, team.getName());
+                World world = event.getEntity().getLocation().getWorld();
+                Location location = event.getEntity().getLocation();
+                tnt.remove();
+                world.spawnParticle(Particle.EXPLOSION_LARGE, location.getX(), location.getY() + 1, location.getZ(), 25);
+                world.playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 20, 2);
+                break;
+            } else {
+                this.arena.getDebugger().i(String.format("Tnt  %s is not the team %s tnt. next.", tnt.getUniqueId(), team.getName()));
             }
         }
     }
diff --git a/src/net/slipcor/pvparena/goals/GoalTank.java b/src/net/slipcor/pvparena/goals/GoalTank.java
index 9117f1176..2e9394080 100644
--- a/src/net/slipcor/pvparena/goals/GoalTank.java
+++ b/src/net/slipcor/pvparena/goals/GoalTank.java
@@ -22,7 +22,6 @@
 import net.slipcor.pvparena.managers.SpawnManager;
 import net.slipcor.pvparena.runnables.EndRunnable;
 import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
@@ -232,29 +231,20 @@ public void commitPlayerDeath(final Player player, final boolean doesRespawn,
             iLives--;
             getLifeMap().put(player.getName(), iLives);
 
-            final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName())
-                    .getArenaTeam();
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                arena.broadcast(Language.parse(arena,
-                        MSG.FIGHT_KILLED_BY_REMAINING,
-                        respawnTeam.colorizePlayer(player) + ChatColor.YELLOW,
-                        arena.parseDeathCause(player, event.getEntity()
-                                        .getLastDamageCause().getCause(),
-                                player.getKiller()), String.valueOf(iLives)));
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING, player, event, iLives);
             }
             final List returned;
 
-            if (arena.getArenaConfig().getBoolean(
+            if (this.arena.getArenaConfig().getBoolean(
                     CFG.PLAYER_DROPSINVENTORY)) {
                 returned = InventoryManager.drop(player);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
-            PACheck.handleRespawn(arena,
-                    ArenaPlayer.parsePlayer(player.getName()), returned);
+            PACheck.handleRespawn(this.arena, ArenaPlayer.parsePlayer(player.getName()), returned);
         }
     }
 
@@ -277,8 +267,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getName()) ? getLifeMap().get(aPlayer
-                            .getName()) : 0));
+                    String.valueOf(getLifeMap().getOrDefault(aPlayer.getName(), 0))
+            );
         }
         return res;
     }
@@ -376,7 +366,7 @@ public void parseStart() {
 
         for (final PASpawn spawn : spawns) {
             if (--pos < 0) {
-                arena.tpPlayerToCoordName(tank.get(), spawn.getName());
+                this.arena.tpPlayerToCoordName(tank, spawn.getName());
                 break;
             }
         }
diff --git a/src/net/slipcor/pvparena/goals/GoalTeamDeathConfirm.java b/src/net/slipcor/pvparena/goals/GoalTeamDeathConfirm.java
index 32d55d0ed..5c756fac2 100644
--- a/src/net/slipcor/pvparena/goals/GoalTeamDeathConfirm.java
+++ b/src/net/slipcor/pvparena/goals/GoalTeamDeathConfirm.java
@@ -11,7 +11,6 @@
 import net.slipcor.pvparena.core.Debug;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
@@ -20,15 +19,13 @@
 import net.slipcor.pvparena.runnables.EndRunnable;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
-import org.bukkit.Material;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityPickupItemEvent;
 import org.bukkit.event.entity.PlayerDeathEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.material.MaterialData;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -183,20 +180,12 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
         }
 
 
-        final ArenaTeam respawnTeam = ArenaPlayer
-                .parsePlayer(respawnPlayer.getName()).getArenaTeam();
+        final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(respawnPlayer.getName()).getArenaTeam();
 
         drop(respawnPlayer, respawnTeam);
 
-        if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-
-            arena.broadcast(Language.parse(arena,
-                    MSG.FIGHT_KILLED_BY,
-                    respawnTeam.colorizePlayer(respawnPlayer)
-                            + ChatColor.YELLOW, arena.parseDeathCause(
-                            respawnPlayer, event.getEntity()
-                                    .getLastDamageCause().getCause(), event
-                                    .getEntity().getKiller())));
+        if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+            this.broadcastSimpleDeathMessage(respawnPlayer, event);
         }
 
         final List returned;
@@ -205,12 +194,10 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
             returned = InventoryManager.drop(respawnPlayer);
             event.getDrops().clear();
         } else {
-            returned = new ArrayList<>();
-            returned.addAll(event.getDrops());
+            returned = new ArrayList<>(event.getDrops());
         }
 
-        PACheck.handleRespawn(arena,
-                ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
+        PACheck.handleRespawn(this.arena, ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
     }
 
     @Override
@@ -220,15 +207,8 @@ public void displayInfo(final CommandSender sender) {
     }
 
     private void drop(final Player player, final ArenaTeam team) {
-        final ItemStack item = StringParser.getItemStackFromString(arena.getArenaConfig().getString(CFG.GOAL_TDC_ITEM));
-
-        if (item.getType() == Material.WOOL || item.getType() == Material.INK_SACK ||
-                item.getType() == Material.STAINED_GLASS || item.getType() == Material.STAINED_CLAY) {
-            final MaterialData data = item.getData();
-            data.setData(getDataFromTeam(team));
-            item.setData(data);
-            item.setDurability(getDataFromTeam(team));
-        }
+        final ItemStack item = arena.getArenaConfig().getItems(CFG.GOAL_TDC_ITEM)[0];
+
         final ItemMeta meta = item.getItemMeta();
 
         meta.setDisplayName(team.getColoredName());
@@ -237,10 +217,6 @@ private void drop(final Player player, final ArenaTeam team) {
         player.getWorld().dropItem(player.getLocation(), item);
     }
 
-    private byte getDataFromTeam(final ArenaTeam team) {
-        return StringParser.getColorDataFromENUM(team.getColor().name());
-    }
-
     @Override
     public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
@@ -248,8 +224,7 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
                     this,
                     String.valueOf(arena.getArenaConfig()
                             .getInt(CFG.GOAL_TDC_LIVES) - (getLifeMap()
-                            .containsKey(aPlayer.getArenaTeam().getName()) ? getLifeMap()
-                            .get(aPlayer.getArenaTeam().getName()) : 0)));
+                            .getOrDefault(aPlayer.getArenaTeam().getName(), 0))));
         }
         return res;
     }
@@ -286,12 +261,12 @@ public boolean isInternal() {
     }
 
     @Override
-    public void onPlayerPickUp(final PlayerPickupItemEvent event) {
+    public void onPlayerPickUp(final EntityPickupItemEvent event) {
         final ItemStack item = event.getItem().getItemStack();
 
-        final ItemStack check = StringParser.getItemStackFromString(arena.getArenaConfig().getString(CFG.GOAL_TDC_ITEM));
+        final ItemStack check = arena.getArenaConfig().getItems(CFG.GOAL_TDC_ITEM)[0];
 
-        final ArenaPlayer player = ArenaPlayer.parsePlayer(event.getPlayer().getName());
+        final ArenaPlayer player = ArenaPlayer.parsePlayer(event.getEntity().getName());
 
         if (item.getType() == check.getType() && item.hasItemMeta()) {
             for (final ArenaTeam team : arena.getTeams()) {
@@ -303,12 +278,12 @@ public void onPlayerPickUp(final PlayerPickupItemEvent event) {
 
                     if (team.equals(player.getArenaTeam())) {
                         // denied a kill
-                        arena.broadcastExcept(event.getPlayer(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_DENIED, player.toString()));
-                        arena.msg(event.getPlayer(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_YOUDENIED, player.toString()));
+                        arena.broadcastExcept(event.getEntity(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_DENIED, player.toString()));
+                        arena.msg(event.getEntity(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_YOUDENIED, player.toString()));
                     } else {
                         // scored a kill
-                        arena.broadcastExcept(event.getPlayer(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_SCORED, player.toString()));
-                        arena.msg(event.getPlayer(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_YOUSCORED, player.toString()));
+                        arena.broadcastExcept(event.getEntity(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_SCORED, player.toString()));
+                        arena.msg(event.getEntity(), Language.parse(arena, MSG.GOAL_TEAMDEATHCONFIRM_YOUSCORED, player.toString()));
                         reduceLives(arena, team);
                     }
                     return;
diff --git a/src/net/slipcor/pvparena/goals/GoalTeamDeathMatch.java b/src/net/slipcor/pvparena/goals/GoalTeamDeathMatch.java
index 51041742c..d9ee609c4 100644
--- a/src/net/slipcor/pvparena/goals/GoalTeamDeathMatch.java
+++ b/src/net/slipcor/pvparena/goals/GoalTeamDeathMatch.java
@@ -252,53 +252,30 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
                 PACheck.handleRespawn(arena,
                         ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
                 ArenaPlayer.parsePlayer(respawnPlayer.getName()).setStatus(Status.LOST);
-
-
-//				arena.getDebugger().i("faking player death", respawnPlayer);
-//				PlayerListener.finallyKillPlayer(arena, respawnPlayer, event);
             }
             return;
 
 
         }
 
-        if (getLifeMap().get(killerTeam.getName()) != null) {
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-
+        if (this.getLifeMap().get(killerTeam.getName()) != null) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
                 if (killerTeam.equals(respawnTeam) || !arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(respawnPlayer)
-                                    + ChatColor.YELLOW, arena.parseDeathCause(
-                                    respawnPlayer, event.getEntity()
-                                            .getLastDamageCause().getCause(), event
-                                            .getEntity().getKiller())));
+                    this.broadcastSimpleDeathMessage(respawnPlayer, event);
                 } else {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY_REMAINING_TEAM_FRAGS,
-                            respawnTeam.colorizePlayer(respawnPlayer)
-                                    + ChatColor.YELLOW, arena.parseDeathCause(
-                                    respawnPlayer, event.getEntity()
-                                            .getLastDamageCause().getCause(), event
-                                            .getEntity().getKiller()), String
-                                    .valueOf(getLifeMap().get(killerTeam.getName())),
-                            killerTeam.getColoredName()));
+                    this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING_TEAM_FRAGS, respawnPlayer, event, this.getLifeMap().get(killerTeam.getName()));
                 }
             }
             final List returned;
 
-            if (arena.getArenaConfig().getBoolean(
-                    CFG.PLAYER_DROPSINVENTORY)) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.PLAYER_DROPSINVENTORY)) {
                 returned = InventoryManager.drop(respawnPlayer);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
-            PACheck.handleRespawn(arena,
-                    ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
-
+            PACheck.handleRespawn(this.arena, ArenaPlayer.parsePlayer(respawnPlayer.getName()), returned);
         }
 
     }
@@ -325,8 +302,7 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
                     this,
                     String.valueOf(arena.getArenaConfig()
                             .getInt(CFG.GOAL_TDM_LIVES) - (getLifeMap()
-                            .containsKey(aPlayer.getArenaTeam().getName()) ? getLifeMap()
-                            .get(aPlayer.getArenaTeam().getName()) : 0)));
+                            .getOrDefault(aPlayer.getArenaTeam().getName(), 0))));
         }
         return res;
     }
diff --git a/src/net/slipcor/pvparena/goals/GoalTeamLives.java b/src/net/slipcor/pvparena/goals/GoalTeamLives.java
index 331749d37..782f743ca 100644
--- a/src/net/slipcor/pvparena/goals/GoalTeamLives.java
+++ b/src/net/slipcor/pvparena/goals/GoalTeamLives.java
@@ -118,10 +118,10 @@ public PACheck checkPlayerDeath(final PACheck res, final Player player) {
             final ArenaTeam respawnTeam = ArenaPlayer
                     .parsePlayer(player.getName()).getArenaTeam();
 
-            if (getLifeMap().get(respawnTeam.getName()) != null) {
+            if (this.getTeamLives(respawnTeam) != null) {
                 return res;
             }
-            if (getLifeMap().get(respawnTeam.getName()) <= 1) {
+            if (this.getTeamLives(respawnTeam) <= 1) {
                 res.setError(this, "0");
             }
 
@@ -185,28 +185,14 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
                 .parsePlayer(respawnPlayer.getName()).getArenaTeam();
         reduceLives(arena, respawnTeam);
 
-        if (getLifeMap().get(respawnTeam.getName()) != null) {
-            if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
-                if (arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY_REMAINING_TEAM,
-                            respawnTeam.colorizePlayer(respawnPlayer)
-                                    + ChatColor.YELLOW, arena.parseDeathCause(
-                                    respawnPlayer, event.getEntity()
-                                            .getLastDamageCause().getCause(), event
-                                            .getEntity().getKiller()), String
-                                    .valueOf(getLifeMap().get(respawnTeam.getName())),
-                            respawnTeam.getColoredName()));
+        if (this.getTeamLives(respawnTeam) != null) {
+            if (this.arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
+                if (this.arena.getArenaConfig().getBoolean(CFG.GENERAL_SHOWREMAININGLIVES)) {
+                    this.broadcastDeathMessage(MSG.FIGHT_KILLED_BY_REMAINING_TEAM, respawnPlayer, event,
+                            this.getTeamLives(respawnTeam));
                 } else {
-                    arena.broadcast(Language.parse(arena,
-                            MSG.FIGHT_KILLED_BY,
-                            respawnTeam.colorizePlayer(respawnPlayer)
-                                    + ChatColor.YELLOW, arena.parseDeathCause(
-                                    respawnPlayer, event.getEntity()
-                                            .getLastDamageCause().getCause(), event
-                                            .getEntity().getKiller())));
+                    this.broadcastSimpleDeathMessage(respawnPlayer, event);
                 }
-
             }
 
             final List returned;
@@ -216,8 +202,7 @@ public void commitPlayerDeath(final Player respawnPlayer, final boolean doesResp
                 returned = InventoryManager.drop(respawnPlayer);
                 event.getDrops().clear();
             } else {
-                returned = new ArrayList<>();
-                returned.addAll(event.getDrops());
+                returned = new ArrayList<>(event.getDrops());
             }
 
             PACheck.handleRespawn(arena,
@@ -250,8 +235,8 @@ public PACheck getLives(final PACheck res, final ArenaPlayer aPlayer) {
         if (res.getPriority() <= PRIORITY + 1000) {
             res.setError(
                     this,
-                    String.valueOf(getLifeMap().containsKey(aPlayer.getArenaTeam().getName()) ? getLifeMap()
-                            .get(aPlayer.getArenaTeam().getName()) : 0));
+                    String.valueOf(getLifeMap().getOrDefault(aPlayer.getArenaTeam().getName(), 0))
+            );
         }
         return res;
     }
@@ -288,7 +273,7 @@ public boolean isInternal() {
     }
 
     private void reduceLives(final Arena arena, final ArenaTeam team) {
-        final int iLives = getLifeMap().get(team.getName());
+        final int iLives = this.getTeamLives(team);
 
         if (iLives <= 1) {
             getLifeMap().remove(team.getName());
@@ -345,8 +330,7 @@ public void setDefaults(final YamlConfiguration config) {
     public Map timedEnd(final Map scores) {
 
         for (final ArenaTeam team : arena.getTeams()) {
-            double score = getLifeMap().containsKey(team.getName()) ? getLifeMap().get(team
-                    .getName()) : 0;
+            double score = this.getLifeMap().containsKey(team.getName()) ? this.getTeamLives(team) : 0;
             if (scores.containsKey(team.getName())) {
                 scores.put(team.getName(), scores.get(team.getName()) + score);
             } else {
@@ -356,4 +340,8 @@ public Map timedEnd(final Map scores) {
 
         return scores;
     }
+
+    private Integer getTeamLives(ArenaTeam respawnTeam) {
+        return this.getLifeMap().get(respawnTeam.getName());
+    }
 }
diff --git a/src/net/slipcor/pvparena/listeners/BlockListener.java b/src/net/slipcor/pvparena/listeners/BlockListener.java
index 8dc4f334c..f7ad96b45 100644
--- a/src/net/slipcor/pvparena/listeners/BlockListener.java
+++ b/src/net/slipcor/pvparena/listeners/BlockListener.java
@@ -12,6 +12,7 @@
 import net.slipcor.pvparena.core.Debug;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
+import net.slipcor.pvparena.core.Utils;
 import net.slipcor.pvparena.loadables.ArenaGoalManager;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
 import net.slipcor.pvparena.loadables.ArenaRegion.RegionProtection;
@@ -21,9 +22,10 @@
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
 import org.bukkit.block.BlockState;
+import org.bukkit.block.data.type.Fire;
 import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
 import org.bukkit.event.*;
 import org.bukkit.event.block.*;
 import org.bukkit.event.entity.ExplosionPrimeEvent;
@@ -31,11 +33,12 @@
 import org.bukkit.event.hanging.HangingPlaceEvent;
 import org.bukkit.event.player.PlayerEvent;
 import org.bukkit.event.world.StructureGrowEvent;
-import org.bukkit.inventory.ItemStack;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static java.util.Arrays.asList;
+
 /**
  * 
  * Block Listener class
@@ -128,8 +131,7 @@ public void onBlockBreak(final BlockBreakEvent event) {
                 && !list.contains(String.valueOf(event.getBlock().getType()
                 .name()))
                 && !list.contains(String.valueOf(event.getBlock().getType()
-                .name())
-                + ':' + event.getBlock().getData())) {
+                .name()))) {
             arena.msg(
                     event.getPlayer(),
                     Language.parse(arena, MSG.ERROR_WHITELIST_DISALLOWED,
@@ -151,8 +153,7 @@ public void onBlockBreak(final BlockBreakEvent event) {
                 new ArrayList()));
 
         if (list.contains(String.valueOf(event.getBlock().getType().name()))
-                || list.contains(String.valueOf(event.getBlock().getType().name())
-                + ':' + event.getBlock().getData())) {
+                || list.contains(String.valueOf(event.getBlock().getType().name()))) {
             arena.msg(
                     event.getPlayer(),
                     Language.parse(arena, MSG.ERROR_BLACKLIST_DISALLOWED,
@@ -397,91 +398,66 @@ public void onBlockPistonExtend(final BlockPistonExtendEvent event) {
 
     @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
     public void onBlockPlace(final BlockPlaceEvent event) {
-        DEBUG.i("BlockPlace", event.getPlayer());
-        if (willBeSkipped(event, event.getBlock().getLocation(),
-                RegionProtection.PLACE)) {
+        final Player player = event.getPlayer();
+        final Block block = event.getBlock();
+
+        DEBUG.i("BlockPlace", player);
+
+        if (willBeSkipped(event, block.getLocation(), RegionProtection.PLACE)) {
             return;
         }
 
-        if (ArenaPlayer.parsePlayer(event.getPlayer().getName()).getStatus() == Status.LOST
-                || ArenaPlayer.parsePlayer(event.getPlayer().getName()).getStatus() == Status.WATCH
-                || ArenaPlayer.parsePlayer(event.getPlayer().getName()).getStatus() == Status.LOUNGE
-                || ArenaPlayer.parsePlayer(event.getPlayer().getName()).getStatus() == Status.READY) {
+        final ArenaPlayer arenaPlayer = ArenaPlayer.parsePlayer(player.getName());
+        if (asList(Status.LOST, Status.WATCH, Status.LOUNGE, Status.READY).contains(arenaPlayer.getStatus())) {
             event.setCancelled(true);
             return;
         }
 
-        final Arena arena = ArenaManager.getArenaByRegionLocation(new PABlockLocation(event
-                .getBlock().getLocation()));
-
-        if (event.getBlock().getType() == Material.TNT && arena.getArenaConfig().getBoolean(CFG.PLAYER_AUTOIGNITE)) {
-            event.setCancelled(true);
-            arena.getDebugger().i("autoignite false");
-
-            class RunLater implements Runnable {
-
-                @Override
-                public void run() {
-                    event.getPlayer().getInventory().remove(new ItemStack(Material.TNT, 1));
-                }
-
-            }
-
-            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RunLater(), 1L);
+        final Arena arena = ArenaManager.getArenaByRegionLocation(new PABlockLocation(block.getLocation()));
+        final Block placedBlock = event.getBlockPlaced();
 
-            event.getBlock().getLocation().getWorld().spawnEntity(
-                    event.getBlock().getRelative(BlockFace.UP).getLocation(), EntityType.PRIMED_TNT);
+        if (block.getType() == Material.TNT && arena.getArenaConfig().getBoolean(CFG.PLAYER_AUTOIGNITE)) {
+            arena.getDebugger().i("autoignite tnt");
+            placedBlock.setType(Material.AIR);
+            block.getWorld().spawnEntity(Utils.getCenteredLocation(block.getLocation()), EntityType.PRIMED_TNT);
             return;
         }
 
 
         List list = arena.getArenaConfig().getStringList(
                 CFG.LISTS_WHITELIST.getNode() + ".place",
-                new ArrayList());
+                new ArrayList<>());
 
-        if (!list.isEmpty()
-                && !list.contains(String.valueOf(event.getBlockPlaced()
-                .getType().name()))
-                && !list.contains(String.valueOf(event.getBlockPlaced()
-                .getType().name())
-                + ':' + event.getBlock().getData())) {
-            arena.msg(
-                    event.getPlayer(),
-                    Language.parse(arena, MSG.ERROR_WHITELIST_DISALLOWED,
-                            Language.parse(arena, MSG.GENERAL_PLACE)));
+        if (!list.isEmpty() && !list.contains(placedBlock.getType().name())) {
+            arena.msg(player, Language.parse(arena, MSG.ERROR_WHITELIST_DISALLOWED, Language.parse(arena, MSG.GENERAL_PLACE)));
             event.setCancelled(true);
             arena.getDebugger().i("not on whitelist. DENY!");
             return;
         }
 
-        if (isProtected(event.getBlock().getLocation(), event,
-                RegionProtection.PLACE)) {
-            if (arena.isFightInProgress()
-                    && !isProtected(event.getBlock().getLocation(), event,
-                    RegionProtection.TNT)
-                    && event.getBlock().getType() == Material.TNT) {
-
-                ArenaModuleManager.onBlockPlace(arena, event.getBlock(), event
-                        .getBlockReplacedState().getType());
+        if (isProtected(block.getLocation(), event, RegionProtection.PLACE)) {
+            if (arena.isFightInProgress() && !isProtected(block.getLocation(), event, RegionProtection.TNT)
+                    && block.getType() == Material.TNT) {
+
+                ArenaModuleManager.onBlockPlace(arena, block, event.getBlockReplacedState().getType());
                 event.setCancelled(false);
                 arena.getDebugger().i("we do not block TNT, so just return if it is TNT");
-                return;
+            } else if (arena.isFightInProgress() && !isProtected(block.getLocation(), event, RegionProtection.FIRE)
+                    && block.getBlockData() instanceof Fire) {
+
+                ArenaModuleManager.onBlockPlace(arena, block, event.getBlockReplacedState().getType());
+                event.setCancelled(false);
+                arena.getDebugger().i("we do not block FIRE, so just return if it is FIRE");
             }
             return;
         }
 
         list = arena.getArenaConfig().getStringList(
                 CFG.LISTS_BLACKLIST.getNode() + ".place",
-                new ArrayList());
+                new ArrayList<>());
 
-        if (list.contains(String.valueOf(event.getBlockPlaced().getType().name()))
-                || list.contains(String.valueOf(event.getBlockPlaced()
-                .getType().name())
-                + ':' + event.getBlock().getData())) {
-            arena.msg(
-                    event.getPlayer(),
-                    Language.parse(arena, MSG.ERROR_BLACKLIST_DISALLOWED,
-                            Language.parse(arena, MSG.GENERAL_PLACE)));
+        if (list.contains(placedBlock.getType().name())) {
+            arena.msg(player, Language.parse(arena, MSG.ERROR_BLACKLIST_DISALLOWED, Language.parse(arena, MSG.GENERAL_PLACE)));
             event.setCancelled(true);
             arena.getDebugger().i("on blacklist. DENY!");
             return;
@@ -490,13 +466,12 @@ public void run() {
         PACheck res = ArenaGoalManager.checkPlace(arena, event);
 
         if (res.hasError()) {
-            DEBUG.i("onBlockPlace cancelled by goal: " + res.getModName(), event.getPlayer());
+            DEBUG.i("onBlockPlace cancelled by goal: " + res.getModName(), player);
             return;
         }
         arena.getDebugger().i("BlockPlace not cancelled!");
 
-        ArenaModuleManager.onBlockPlace(arena, event.getBlock(), event
-                .getBlockReplacedState().getType());
+        ArenaModuleManager.onBlockPlace(arena, block, event.getBlockReplacedState().getType());
     }
 
     @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@@ -537,11 +512,11 @@ public void onBlockBreak(final HangingBreakEvent event) {
             return;
         }
         if (arena == null) {
-            DEBUG.i("painting break inside the arena");
-        } else {
-            arena.getDebugger().i("painting break inside the arena");
+            DEBUG.i("painting break outside an arena");
+            return;
         }
-        ArenaModuleManager.onPaintingBreak(arena, event.getEntity(), event
-                .getEntity().getType());
+
+        arena.getDebugger().i("painting break inside an arena");
+        ArenaModuleManager.onPaintingBreak(arena, event.getEntity(), event.getEntity().getType());
     }
-}
\ No newline at end of file
+}
diff --git a/src/net/slipcor/pvparena/listeners/EntityListener.java b/src/net/slipcor/pvparena/listeners/EntityListener.java
index 8bc9c57ff..d19a722dd 100644
--- a/src/net/slipcor/pvparena/listeners/EntityListener.java
+++ b/src/net/slipcor/pvparena/listeners/EntityListener.java
@@ -281,6 +281,14 @@ public void onEntityDamageByEntity(final EntityDamageByEntityEvent event) {
             return;
         }
 
+        // cancel if defender or attacker are not fighting
+        if (apAttacker.getStatus() != Status.FIGHT || apDefender.getStatus() != Status.FIGHT ) {
+            arena.getDebugger().i("player or target is not fighting, cancel!", attacker);
+            arena.getDebugger().i("player or target is not fighting, cancel!", defender);
+            event.setCancelled(true);
+            return;
+        }
+
         Bukkit.getScheduler().scheduleSyncDelayedTask(PVPArena.instance,
                 new DamageResetRunnable(arena, attacker, defender), 1L);
 
@@ -309,6 +317,32 @@ public void onEntityDamageByEntity(final EntityDamageByEntityEvent event) {
         }
     }
 
+    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+    public void onProjectileHitEvent(final ProjectileHitEvent event) {
+        ProjectileSource eDamager = event.getEntity().getShooter();
+        final Entity eDamagee = event.getHitEntity();
+
+
+        if (eDamager instanceof Player && ArenaPlayer.parsePlayer(((Player) eDamager).getName()).getStatus() == Status.LOST) {
+            return;
+        }
+
+        if(eDamager instanceof Player && eDamagee instanceof Player) {
+            final Player attacker = (Player) eDamager;
+            final Player defender = (Player) eDamagee;
+            final ArenaPlayer apDefender = ArenaPlayer.parsePlayer(defender.getName());
+            final ArenaPlayer apAttacker = ArenaPlayer.parsePlayer(attacker.getName());
+            final Arena arena = apDefender.getArena();
+
+            if (arena == null || apAttacker.getArena() == null || apDefender.getStatus() == Status.LOST || !arena.isFightInProgress()) {
+                return;
+            }
+
+            arena.getDebugger().i("onProjectileHitEvent: fighting player");
+            ArenaModuleManager.onProjectileHit(arena, attacker, defender, event);
+        }
+    }
+
     @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
     public void onEntityDamage(final EntityDamageEvent event) {
         final Entity entity = event.getEntity();
@@ -448,10 +482,10 @@ public void onPotionSplash(final PotionSplashEvent event) {
             if (damagee.getArena() == null || shooter.getArena() == null ||
                     (damagee.getArena() != shooter.getArena()) ||
                     damagee.getArenaTeam() == null || shooter.getArenaTeam() == null) {
-                /**
-                 * some people obviously allow non arena players to mess with potions around arena players
-                 *
-                 * this check should cover any of the entities not being in the same arena, or not arena at all
+                /*
+                  some people obviously allow non arena players to mess with potions around arena players
+
+                  this check should cover any of the entities not being in the same arena, or not arena at all
                  */
                 DEBUG.i("skipping "+e.getName());
                 continue;
diff --git a/src/net/slipcor/pvparena/listeners/PlayerListener.java b/src/net/slipcor/pvparena/listeners/PlayerListener.java
index 92ab5d06e..c096b4e92 100644
--- a/src/net/slipcor/pvparena/listeners/PlayerListener.java
+++ b/src/net/slipcor/pvparena/listeners/PlayerListener.java
@@ -16,7 +16,6 @@
 import net.slipcor.pvparena.core.Debug;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
 import net.slipcor.pvparena.events.PAGoalEvent;
 import net.slipcor.pvparena.loadables.ArenaGoalManager;
 import net.slipcor.pvparena.loadables.ArenaModule;
@@ -47,6 +46,8 @@
 
 import java.util.*;
 
+import static java.util.Arrays.asList;
+
 /**
  * 
  * Player Listener class
@@ -70,11 +71,10 @@ private boolean checkAndCommitCancel(final Arena arena, final Player player,
             return false;
         }
         final PlayerInteractEvent pie = (PlayerInteractEvent) event;
-        final Material mat = pie.getClickedBlock().getType();
-        final Material check = arena == null ? Material.IRON_BLOCK : arena
-                .getReadyBlock();
-        if (mat == Material.SIGN || mat == Material.SIGN_POST
-                || mat == Material.WALL_SIGN || mat == check) {
+        final Block block = pie.getClickedBlock();
+        final Material check = arena == null ? Material.IRON_BLOCK : arena.getReadyBlock();
+
+        if (block != null && (block.getState() instanceof Sign || block.getType() == check)) {
             DEBUG.i("signs and ready blocks allowed!", player);
             DEBUG.i("> false", player);
             return false;
@@ -320,8 +320,6 @@ public void onPlayerDropItem(final PlayerDropItemEvent event) {
             return; // no drop protection
         }
 
-        arena.getDebugger().i("item: "+ StringParser.getStringFromItemStack(event.getItemDrop().getItemStack()));
-
         if (Bukkit.getPlayer(player.getName()) == null || aPlayer.getStatus() == Status.DEAD || aPlayer.getStatus() == Status.LOST) {
             arena.getDebugger().i("Player is dead. allowing drops!");
             return;
@@ -385,7 +383,7 @@ public static void finallyKillPlayer(final Arena arena, final Player player,
         final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName());
         final ArenaTeam team = aPlayer.getArenaTeam();
 
-        final String playerName = team == null ? player.getName() : team.colorizePlayer(player);
+        final String playerName = (team == null) ? player.getName() : team.colorizePlayer(player);
         if (arena.getArenaConfig().getBoolean(CFG.USES_DEATHMESSAGES)) {
             arena.broadcast(Language.parse(arena,
                     MSG.FIGHT_KILLED_BY,
@@ -401,14 +399,14 @@ public static void finallyKillPlayer(final Arena arena, final Player player,
             }
         }
 
-        if (ArenaPlayer.parsePlayer(player.getName()).getArenaClass() == null
-                || !"custom".equalsIgnoreCase(ArenaPlayer.parsePlayer(player.getName()).getArenaClass()
-                .getName())) {
+        // Trick to avoid death screen
+        Bukkit.getScheduler().scheduleSyncDelayedTask(PVPArena.instance, player::closeInventory, 1);
+
+        if (!aPlayer.hasCustomClass()) {
             InventoryManager.clearInventory(player);
         }
 
-        arena.removePlayer(player,
-                arena.getArenaConfig().getString(CFG.TP_DEATH), true, false);
+        arena.removePlayer(player, arena.getArenaConfig().getString(CFG.TP_DEATH), true, false);
 
         aPlayer.setStatus(Status.LOST);
         aPlayer.addDeath();
@@ -530,7 +528,11 @@ public void onPlayerInteract(final PlayerInteractEvent event) {
             if (whyMe) {
                 arena.getDebugger().i("exiting! fight in progress AND no INBATTLEJOIN arena!", player); return;
             }
-            if (aPlayer.getStatus() != Status.LOUNGE && aPlayer.getStatus() != Status.READY) {
+            if (asList(Status.LOUNGE, Status.READY).contains(aPlayer.getStatus()) &&
+                    arena.getArenaConfig().getBoolean(CFG.PERMS_LOUNGEINTERACT)) {
+                arena.getDebugger().i("allowing lounge interaction due to config setting!");
+                event.setCancelled(false);
+            } else if (aPlayer.getStatus() != Status.LOUNGE && aPlayer.getStatus() != Status.READY) {
                 arena.getDebugger().i("cancelling: not fighting nor in the lounge", player);
                 event.setCancelled(true);
             } else if (aPlayer.getArena() != null && team != null) {
@@ -574,7 +576,8 @@ public void onPlayerInteract(final PlayerInteractEvent event) {
             }
 
             if (whyMe) {
-                arena.getDebugger().i("exiting! fight in progress AND no INBATTLEJOIN arena!", player); return;
+                arena.getDebugger().i("exiting! fight in progress AND no INBATTLEJOIN arena!", player);
+                return;
             }
             arena.getDebugger().i("block click!", player);
 
@@ -669,7 +672,7 @@ public void run() {
                 for (final PASpawn spawn : spawns) {
 
                     if (--pos < 0) {
-                        arena.tpPlayerToCoordName(player, spawn.getName());
+                        arena.tpPlayerToCoordName(aPlayer, spawn.getName());
                         break;
                     }
                 }
@@ -753,12 +756,9 @@ public void onPlayerJoin(final PlayerJoinEvent event) {
             arena.playerLeave(player, CFG.TP_EXIT, true, true, false);
         }
 
-        if (!player.isOp()) {
-            return; // no OP => OUT
-        }
         DEBUG.i("OP joins the game", player);
-        if (PVPArena.instance.getUpdater() != null) {
-            PVPArena.instance.getUpdater().message(player);
+        if (player.isOp() && PVPArena.instance.getUpdateChecker() != null) {
+            PVPArena.instance.getUpdateChecker().displayMessage(player);
         }
     }
 
@@ -796,8 +796,11 @@ public void onPlayerRespawn(final PlayerRespawnEvent event) {
     }
 
     @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
-    public void onPlayerPickupItem(final PlayerPickupItemEvent event) {
-        final Player player = event.getPlayer();
+    public void onPlayerPickupItem(final EntityPickupItemEvent event) {
+        if (!(event.getEntity() instanceof Player)) {
+            return;
+        }
+        final Player player = (Player) event.getEntity();
 
         if (willBeCancelled(player, event)) {
             return;
@@ -927,7 +930,7 @@ class RunLater implements Runnable {
                 public void run() {
                     for (final ArenaPlayer otherPlayer : arena.getFighters()) {
                         if (otherPlayer.get() != null) {
-                            otherPlayer.get().showPlayer(player);
+                            otherPlayer.get().showPlayer(PVPArena.instance, player);
                         }
                     }
                 }
diff --git a/src/net/slipcor/pvparena/loadables/ArenaGoal.java b/src/net/slipcor/pvparena/loadables/ArenaGoal.java
index 470a1672e..98058df74 100644
--- a/src/net/slipcor/pvparena/loadables/ArenaGoal.java
+++ b/src/net/slipcor/pvparena/loadables/ArenaGoal.java
@@ -9,7 +9,9 @@
 import net.slipcor.pvparena.commands.CommandTree;
 import net.slipcor.pvparena.core.Config.CFG;
 import net.slipcor.pvparena.core.Debug;
+import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.ncloader.NCBLoadable;
+import org.bukkit.ChatColor;
 import org.bukkit.block.Block;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.YamlConfiguration;
@@ -17,14 +19,16 @@
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.event.block.BlockPlaceEvent;
 import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityPickupItemEvent;
 import org.bukkit.event.entity.PlayerDeathEvent;
 import org.bukkit.event.inventory.CraftItemEvent;
 import org.bukkit.event.inventory.InventoryClickEvent;
 import org.bukkit.event.player.PlayerDropItemEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 
 import java.util.*;
 
+import static java.util.Optional.ofNullable;
+
 /**
  * 
  * Arena Goal class
@@ -115,7 +119,7 @@ public PACheck checkInventory(PACheck result, Arena arena, InventoryClickEvent e
         return result;
     }
 
-    public PACheck checkPickup(PACheck result, Arena arena, PlayerPickupItemEvent event) {
+    public PACheck checkPickup(PACheck result, Arena arena, EntityPickupItemEvent event) {
         return result;
     }
 
@@ -155,7 +159,8 @@ protected String checkForMissingSpawn(final Set list) {
                 count++;
             }
         }
-        return count > 3 ? null : "need more spawns! (" + count + "/4)";
+        int minPlayers = this.arena.getArenaConfig().getInt(CFG.READY_MINPLAYERS);
+        return count >= minPlayers ? null : "need more spawns! (" + count + "/" + minPlayers + ")";
     }
 
     /**
@@ -408,7 +413,7 @@ public void lateJoin(final Player player) {
     public void onThisLoad() {
     }
 
-    public void onPlayerPickUp(final PlayerPickupItemEvent event) {
+    public void onPlayerPickUp(final EntityPickupItemEvent event) {
     }
 
     /**
@@ -527,4 +532,30 @@ protected void updateLives(final Player player, final int value) {
             getLifeMap().put(player.getName(), value);
         }
     }
+
+    protected void broadcastSimpleDeathMessage(Player player, PlayerDeathEvent event) {
+        this.broadcastDeathMessage(Language.MSG.FIGHT_KILLED_BY, player, event, null);
+    }
+
+    protected void broadcastDeathMessage(Language.MSG deathMessage, Player player, PlayerDeathEvent event, Integer remainingLives) {
+        final ArenaTeam respawnTeam = ArenaPlayer.parsePlayer(player.getName()).getArenaTeam();
+
+        EntityDamageEvent.DamageCause damageCause = ofNullable(event.getEntity().getLastDamageCause())
+                .map(EntityDamageEvent::getCause)
+                .orElse(null);
+        String deathCause = this.arena.parseDeathCause(player, damageCause, event.getEntity().getKiller());
+        String coloredPlayerName = respawnTeam.colorizePlayer(player) + ChatColor.YELLOW;
+
+        if(deathMessage == Language.MSG.FIGHT_KILLED_BY_REMAINING || deathMessage == Language.MSG.FIGHT_KILLED_BY_REMAINING_FRAGS) {
+            this.arena.broadcast(Language.parse(this.arena, deathMessage,
+                    coloredPlayerName, deathCause, String.valueOf(remainingLives)));
+        } else if(deathMessage == Language.MSG.FIGHT_KILLED_BY_REMAINING_TEAM || deathMessage == Language.MSG.FIGHT_KILLED_BY_REMAINING_TEAM_FRAGS) {
+            this.arena.broadcast(Language.parse(this.arena, deathMessage,
+                    coloredPlayerName,deathCause, String.valueOf(remainingLives),
+                    respawnTeam.getColoredName()));
+        } else {
+            this.arena.broadcast(Language.parse(this.arena, Language.MSG.FIGHT_KILLED_BY,
+                    coloredPlayerName, deathCause));
+        }
+    }
 }
diff --git a/src/net/slipcor/pvparena/loadables/ArenaGoalManager.java b/src/net/slipcor/pvparena/loadables/ArenaGoalManager.java
index 0aa81a998..b6508ea8b 100644
--- a/src/net/slipcor/pvparena/loadables/ArenaGoalManager.java
+++ b/src/net/slipcor/pvparena/loadables/ArenaGoalManager.java
@@ -16,10 +16,10 @@
 import org.bukkit.entity.Player;
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.EntityPickupItemEvent;
 import org.bukkit.event.inventory.CraftItemEvent;
 import org.bukkit.event.inventory.InventoryClickEvent;
 import org.bukkit.event.player.PlayerDropItemEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 
 import java.io.File;
 import java.util.*;
@@ -133,10 +133,12 @@ public static PACheck checkInventory(Arena arena, InventoryClickEvent event) {
         return result;
     }
 
-    public static PACheck checkPickup(Arena arena, PlayerPickupItemEvent event) {
+    public static PACheck checkPickup(Arena arena, EntityPickupItemEvent event) {
         PACheck result = new PACheck();
-        for (final ArenaGoal type : arena.getGoals()) {
-            result = type.checkPickup(result, arena, event);
+        if (event.getEntity() instanceof Player) {
+            for (final ArenaGoal type : arena.getGoals()) {
+                result = type.checkPickup(result, arena, event);
+            }
         }
         return result;
     }
@@ -245,10 +247,10 @@ public void setPlayerLives(final Arena arena, final ArenaPlayer player,
 
     public void timedEnd(final Arena arena) {
 
-        /**
-         * name/team => score points
-         *
-         * handed over to each module
+        /*
+          name/team => score points
+
+          handed over to each module
          */
 
         arena.getDebugger().i("timed end!");
@@ -504,9 +506,11 @@ public static void lateJoin(final Arena arena, final Player player) {
         }
     }
 
-    public static void onPlayerPickUp(final Arena arena, final PlayerPickupItemEvent event) {
-        for (final ArenaGoal goal : arena.getGoals()) {
-            goal.onPlayerPickUp(event);
+    public static void onPlayerPickUp(final Arena arena, final EntityPickupItemEvent event) {
+        if (event.getEntity() instanceof Player) {
+            for (final ArenaGoal goal : arena.getGoals()) {
+                goal.onPlayerPickUp(event);
+            }
         }
     }
 }
diff --git a/src/net/slipcor/pvparena/loadables/ArenaModule.java b/src/net/slipcor/pvparena/loadables/ArenaModule.java
index 61210a6cc..b6999d904 100644
--- a/src/net/slipcor/pvparena/loadables/ArenaModule.java
+++ b/src/net/slipcor/pvparena/loadables/ArenaModule.java
@@ -20,13 +20,9 @@
 import org.bukkit.entity.EntityType;
 import org.bukkit.entity.Hanging;
 import org.bukkit.entity.Player;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
-import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.*;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
-import org.bukkit.event.entity.EntityExplodeEvent;
-import org.bukkit.event.entity.EntityRegainHealthEvent;
 import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 import org.bukkit.event.player.PlayerVelocityEvent;
 import org.bukkit.inventory.ItemStack;
 
@@ -44,7 +40,7 @@
  * @author slipcor
  */
 
-public class ArenaModule extends NCBLoadable implements IArenaCommandHandler {
+public abstract class ArenaModule extends NCBLoadable implements IArenaCommandHandler {
     protected static Debug debug = new Debug(32);
 
     protected Arena arena;
@@ -292,6 +288,17 @@ public void onEntityDamageByEntity(final Player attacker,
                                        final Player defender, final EntityDamageByEntityEvent event) {
     }
 
+    /**
+     * hook into a player throwing projectile
+     *
+     * @param attacker the attacking player
+     * @param defender the attacked player
+     * @param event    the projectileHit event
+     */
+    public void onProjectileHit(final Player attacker, final Player defender, final ProjectileHitEvent event) {
+
+    }
+
     /**
      * hook into an exploding entity
      *
@@ -332,7 +339,7 @@ public boolean onPlayerInteract(final PlayerInteractEvent event) {
      *
      * @param event the pickup event
      */
-    public void onPlayerPickupItem(final PlayerPickupItemEvent event) {
+    public void onPlayerPickupItem(final EntityPickupItemEvent event) {
     }
 
     /**
@@ -418,18 +425,6 @@ public Integer parseStartCountDown(Integer seconds, String message, Boolean glob
     public void reset(final boolean force) {
     }
 
-    /**
-     * hook into an arena player being reset
-     *
-     * @deprecated use {@link #resetPlayer(Player, boolean, boolean)}
-     *
-     * @param player the player being reset
-     * @param force  if the arena is forcefully reset
-     */
-    @Deprecated
-    public void resetPlayer(final Player player, final boolean force) {
-    }
-
     /**
      * hook into an arena player being reset
      *
@@ -497,6 +492,16 @@ public boolean tryDeathOverride(final ArenaPlayer aPlayer,
         return false;
     }
 
+    /**
+     * Call a special leave directly from the module
+     *
+     * @param aPlayer the player who leaves
+     * @return true if a module cares
+     */
+    public boolean handleSpecialLeave(final ArenaPlayer aPlayer) {
+        return false;
+    }
+
     /**
      * hook into a player removal
      *
diff --git a/src/net/slipcor/pvparena/loadables/ArenaModuleManager.java b/src/net/slipcor/pvparena/loadables/ArenaModuleManager.java
index 4fc4aebfe..55ab50da5 100644
--- a/src/net/slipcor/pvparena/loadables/ArenaModuleManager.java
+++ b/src/net/slipcor/pvparena/loadables/ArenaModuleManager.java
@@ -15,13 +15,9 @@
 import org.bukkit.entity.EntityType;
 import org.bukkit.entity.Hanging;
 import org.bukkit.entity.Player;
-import org.bukkit.event.entity.EntityDamageByEntityEvent;
-import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.*;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
-import org.bukkit.event.entity.EntityExplodeEvent;
-import org.bukkit.event.entity.EntityRegainHealthEvent;
 import org.bukkit.event.player.PlayerInteractEvent;
-import org.bukkit.event.player.PlayerPickupItemEvent;
 import org.bukkit.event.player.PlayerVelocityEvent;
 
 import java.io.File;
@@ -177,6 +173,12 @@ public static void onEntityDamageByEntity(final Arena arena, final Player attack
         }
     }
 
+    public static void onProjectileHit(final Arena arena, final Player attacker, final Player defender, final ProjectileHitEvent event) {
+        for (final ArenaModule mod : arena.getMods()) {
+            mod.onProjectileHit(attacker, defender, event);
+        }
+    }
+
     public static void onEntityExplode(final Arena arena, final EntityExplodeEvent event) {
         for (final ArenaModule mod : arena.getMods()) {
             mod.onEntityExplode(event);
@@ -204,9 +206,11 @@ public static boolean onPlayerInteract(final Arena arena, final PlayerInteractEv
         return false;
     }
 
-    public static void onPlayerPickupItem(final Arena arena, final PlayerPickupItemEvent event) {
-        for (final ArenaModule mod : arena.getMods()) {
-            mod.onPlayerPickupItem(event);
+    public static void onPlayerPickupItem(final Arena arena, final EntityPickupItemEvent event) {
+        if (event.getEntity() instanceof Player) {
+            for (final ArenaModule mod : arena.getMods()) {
+                mod.onPlayerPickupItem(event);
+            }
         }
     }
 
@@ -269,16 +273,6 @@ public static void reset(final Arena arena, final boolean force) {
         }
     }
 
-    /**
-     * @deprecated use {@link #resetPlayer(Arena, Player, boolean, boolean)}
-     */
-    @Deprecated
-    public static void resetPlayer(final Arena arena, final Player player, final boolean force) {
-        for (final ArenaModule mod : arena.getMods()) {
-            mod.resetPlayer(player, force);
-        }
-    }
-
     public static void resetPlayer(final Arena arena, final Player player, final boolean soft, final boolean force) {
         for (final ArenaModule mod : arena.getMods()) {
             mod.resetPlayer(player, soft, force);
diff --git a/src/net/slipcor/pvparena/loadables/ArenaRegion.java b/src/net/slipcor/pvparena/loadables/ArenaRegion.java
index 10b01edc6..8aa4a4812 100644
--- a/src/net/slipcor/pvparena/loadables/ArenaRegion.java
+++ b/src/net/slipcor/pvparena/loadables/ArenaRegion.java
@@ -1,6 +1,5 @@
 package net.slipcor.pvparena.loadables;
 
-import com.google.common.collect.ImmutableMap;
 import net.slipcor.pvparena.PVPArena;
 import net.slipcor.pvparena.arena.Arena;
 import net.slipcor.pvparena.arena.ArenaPlayer;
@@ -30,9 +29,12 @@
 import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
 import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.scheduler.BukkitTask;
 
 import java.util.*;
 
+import static java.util.Arrays.asList;
+
 public class ArenaRegion {
 
     private static final Debug debug = new Debug(34);
@@ -40,7 +42,7 @@ public class ArenaRegion {
     private Arena arena;
     private String name;
     private RegionType type;
-    private int tickID = -1;
+    private BukkitTask runningTask;
     private final Set flags = new HashSet<>();
     private final Set protections = new HashSet<>();
     private final Map playerLocations = new HashMap<>();
@@ -200,7 +202,7 @@ public static boolean checkRegionSetPosition(final PlayerInteractEvent event,
                 && (PVPArena.hasAdminPerms(player) || PVPArena.hasCreatePerms(
                 player, arena))
                 && player.getEquipment().getItemInMainHand() != null
-                && player.getEquipment().getItemInMainHand().getType().name().equals(arena
+                && player.getEquipment().getItemInMainHand().getType().toString().equals(arena
                 .getArenaConfig().getString(CFG.GENERAL_WAND))) {
             // - modify mode is active
             // - player has admin perms
@@ -368,19 +370,15 @@ public String getWorldName() {
 
     public void initTimer() {
 
-        if (tickID != -1) {
-            if (type == RegionType.JOIN || type == RegionType.WATCH) {
-                return;
+        if (this.runningTask != null && !this.runningTask.isCancelled()) {
+            if (!asList(RegionType.JOIN, RegionType.WATCH, RegionType.LOUNGE).contains(this.type)) {
+                this.runningTask.cancel();
             }
-
-            Bukkit.getScheduler().cancelTask(tickID);
         }
 
         final RegionRunnable regionRunner = new RegionRunnable(this);
-        tickID = Bukkit.getScheduler().scheduleSyncRepeatingTask(
-                PVPArena.instance, regionRunner,
-                (long) arena.getArenaConfig().getInt(CFG.TIME_REGIONTIMER),
-                (long) arena.getArenaConfig().getInt(CFG.TIME_REGIONTIMER));
+        final int timer = this.arena.getArenaConfig().getInt(CFG.TIME_REGIONTIMER);
+        this.runningTask = regionRunner.runTaskTimer(PVPArena.instance, timer, timer);
     }
 
     public boolean isInNoWoolSet(final Block block) {
@@ -447,16 +445,12 @@ public void reset() {
     }
 
     public void removeEntities() {
-        if (getWorld() == null || getWorld().getEntities() == null) {
+        if (getWorld() == null || getWorld().getEntities().isEmpty()) {
             return;
         }
 
         for (final Entity entity : getWorld().getEntities()) {
-            if (entity instanceof Player
-                    || !shape.contains(new PABlockLocation(entity.getLocation()
-                    .getWorld().getName(), entity.getLocation().getBlockX(),
-                    entity.getLocation().getBlockY(), entity.getLocation()
-                    .getBlockZ()))) {
+            if (entity instanceof Player || !shape.contains(new PABlockLocation(entity.getLocation()))) {
                 continue;
             }
 
@@ -478,8 +472,9 @@ public void removeEntities() {
             return;
         }
 
-        Bukkit.getScheduler().cancelTask(tickID);
-        tickID = -1;
+        if(this.runningTask != null && !this.runningTask.isCancelled()) {
+            this.runningTask.cancel();
+        }
     }
 
     public void saveToConfig() {
@@ -521,7 +516,7 @@ public void tick() {
                 }
                 ap.get().setLastDamageCause(
                         new EntityDamageEvent(ap.get(), DamageCause.CUSTOM,
-                                new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(1003))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0))));
+                                1003.0));
                 ap.get().damage(1000);
             }
             if (flags.contains(RegionFlag.WIN) && shape.contains(pLoc)) {
@@ -540,8 +535,7 @@ public void tick() {
                             Bukkit.getWorld(world).strikeLightningEffect(
                                     ap2.get().getLocation());
                             final EntityDamageEvent event = new EntityDamageEvent(
-                                    ap2.get(), DamageCause.LIGHTNING,
-                                    new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0)));
+                                    ap2.get(), DamageCause.LIGHTNING, 10.0);
                             PlayerListener.finallyKillPlayer(arena,
                                     ap2.get(), event);
                         }
@@ -555,8 +549,7 @@ public void tick() {
                         Bukkit.getWorld(world).strikeLightningEffect(
                                 ap.get().getLocation());
                         final EntityDamageEvent event = new EntityDamageEvent(
-                                ap.get(), DamageCause.LIGHTNING,
-                                new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0)));
+                                ap.get(), DamageCause.LIGHTNING, 10.0);
                         PlayerListener
                                 .finallyKillPlayer(arena, ap.get(), event);
                     }
@@ -572,8 +565,7 @@ public void tick() {
                                         .strikeLightningEffect(
                                                 ap2.get().getLocation());
                                 final EntityDamageEvent event = new EntityDamageEvent(
-                                        ap2.get(), DamageCause.LIGHTNING,
-                                        new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(10))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0)));
+                                        ap2.get(), DamageCause.LIGHTNING,10.0);
                                 PlayerListener.finallyKillPlayer(arena,
                                         ap2.get(), event);
                             }
@@ -592,8 +584,7 @@ public void tick() {
                         if (loc.distance(ap.get().getLocation()) < 3) {
                             ap.get().setLastDamageCause(
                                     new EntityDamageEvent(ap.get(),
-                                            DamageCause.CUSTOM,
-                                            new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(arena.getArenaConfig().getInt(CFG.DAMAGE_SPAWNCAMP)))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0))));
+                                            DamageCause.CUSTOM, arena.getArenaConfig().getInt(CFG.DAMAGE_SPAWNCAMP)));
                             ap.get().damage(
                                     arena.getArenaConfig().getInt(
                                             CFG.DAMAGE_SPAWNCAMP));
@@ -627,8 +618,7 @@ public void tick() {
                             CFG.GENERAL_LEAVEDEATH)) {
                         ap.get().setLastDamageCause(
                                 new EntityDamageEvent(ap.get(),
-                                        DamageCause.CUSTOM,
-                                        new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, Double.valueOf(1004))), new EnumMap(ImmutableMap.of(EntityDamageEvent.DamageModifier.BASE, 0))));
+                                        DamageCause.CUSTOM, 1004.0));
                         // ap.get().setHealth(0);
                         ap.get().damage(1000);
                     } else {
diff --git a/src/net/slipcor/pvparena/managers/ArenaManager.java b/src/net/slipcor/pvparena/managers/ArenaManager.java
index 5fb4c3059..cbfa8a2ae 100644
--- a/src/net/slipcor/pvparena/managers/ArenaManager.java
+++ b/src/net/slipcor/pvparena/managers/ArenaManager.java
@@ -185,6 +185,22 @@ public static Arena getArenaByName(final String name) {
         return null;
     }
 
+    public static Arena getArenaByExactName(final String name) {
+        if (name == null || name.isEmpty()) {
+            return null;
+        }
+        final String sName = name.toLowerCase();
+        final Arena arena = ARENAS.get(sName);
+        if (arena != null) {
+            return arena;
+        }
+        return ARENAS.entrySet().stream()
+                .filter(e -> name.equalsIgnoreCase(e.getKey()))
+                .findFirst()
+                .map(Map.Entry::getValue)
+                .orElse(null);
+    }
+
     /**
      * search the arenas by location
      *
@@ -243,11 +259,7 @@ public static Set getArenasByRegionLocation(
      * @return a Set of Arena
      */
     public static Set getArenas() {
-        final Set arenas = new HashSet<>();
-        for (final Arena a : ARENAS.values()) {
-            arenas.add(a);
-        }
-        return arenas;
+        return new HashSet<>(ARENAS.values());
     }
 
     /**
diff --git a/src/net/slipcor/pvparena/managers/ConfigurationManager.java b/src/net/slipcor/pvparena/managers/ConfigurationManager.java
index fc88bc3d5..966cd23c5 100644
--- a/src/net/slipcor/pvparena/managers/ConfigurationManager.java
+++ b/src/net/slipcor/pvparena/managers/ConfigurationManager.java
@@ -11,7 +11,7 @@
 import net.slipcor.pvparena.core.Config.CFG;
 import net.slipcor.pvparena.core.Language;
 import net.slipcor.pvparena.core.Language.MSG;
-import net.slipcor.pvparena.core.StringParser;
+import net.slipcor.pvparena.core.Utils;
 import net.slipcor.pvparena.loadables.ArenaGoal;
 import net.slipcor.pvparena.loadables.ArenaModule;
 import net.slipcor.pvparena.loadables.ArenaModuleManager;
@@ -19,14 +19,13 @@
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
 import org.bukkit.block.Chest;
-import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.inventory.ItemStack;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.*;
 
+import static net.slipcor.pvparena.core.ItemStackUtils.getItemStacksFromConfig;
+
 /**
  * 
  * Configuration Manager class
@@ -130,19 +129,34 @@ public static boolean configParse(final Arena arena, final Config cfg) {
 
         if (config.get("classitems") == null) {
             if (PVPArena.instance.getConfig().get("classitems") == null) {
-                config.addDefault("classitems.Ranger",
-                        "BOW,ARROW:64,LEATHER_HELMET,LEATHER_CHESTPLATE,LEATHER_LEGGINGS,LEATHER_BOOTS");
-                config.addDefault("classitems.Swordsman",
-                        "DIAMOND_SWORD,IRON_HELMET,IRON_CHESTPLATE,IRON_LEGGINGS,IRON_BOOTS");
-                config.addDefault("classitems.Tank",
-                        "STONE_SWORD,DIAMOND_HELMET,DIAMOND_CHESTPLATE,DIAMOND_LEGGINGS,DIAMOND_BOOTS");
-                config.addDefault("classitems.Pyro",
-                        "FLINT_AND_STEEL,TNT:3,LEATHER_HELMET,LEATHER_CHESTPLATE,LEATHER_LEGGINGS,LEATHER_BOOTS");
-            } else {
-                for (final String key : PVPArena.instance.getConfig().getKeys(false)) {
-                    config.addDefault("classitems." + key, PVPArena.instance
-                            .getConfig().get("classitems." + key));
-                }
+                config.addDefault("classitems.Ranger.items",
+                        Utils.getItemStacksFromMaterials(Material.BOW, Material.ARROW));
+                config.addDefault("classitems.Ranger.offhand",
+                        Utils.getItemStacksFromMaterials(Material.AIR));
+                config.addDefault("classitems.Ranger.armor",
+                        Utils.getItemStacksFromMaterials(Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS));
+
+                config.addDefault("classitems.Swordsman.items",
+                        Utils.getItemStacksFromMaterials(Material.DIAMOND_SWORD));
+                config.addDefault("classitems.Swordsman.offhand",
+                        Utils.getItemStacksFromMaterials(Material.AIR));
+                config.addDefault("classitems.Swordsman.armor",
+                        Utils.getItemStacksFromMaterials(Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS));
+
+                config.addDefault("classitems.Tank.items",
+                        Utils.getItemStacksFromMaterials(Material.STONE_SWORD));
+                config.addDefault("classitems.Tank.offhand",
+                        Utils.getItemStacksFromMaterials(Material.AIR));
+                config.addDefault("classitems.Tank.armor",
+                        Utils.getItemStacksFromMaterials(Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS));
+
+                config.addDefault("classitems.Pyro.items",
+                        Utils.getItemStacksFromMaterials(Material.FLINT_AND_STEEL, Material.TNT, Material.TNT, Material.TNT));
+                config.addDefault("classitems.Pyro.offhand",
+                        Utils.getItemStacksFromMaterials(Material.AIR));
+                config.addDefault("classitems.Pyro.armor",
+                        Utils.getItemStacksFromMaterials(Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS));
+
             }
         }
 
@@ -173,8 +187,6 @@ public static boolean configParse(final Arena arena, final Config cfg) {
 
         config.options().copyDefaults(true);
 
-        updateItemIDs(cfg, "1.0.6.198");
-
         cfg.set(CFG.Z, "1.3.3.217");
         cfg.save();
         cfg.load();
@@ -185,14 +197,19 @@ public static boolean configParse(final Arena arena, final Config cfg) {
         arena.getDebugger().i("reading class items");
         ArenaClass.addGlobalClasses(arena);
         for (final Map.Entry stringObjectEntry1 : classes.entrySet()) {
-            final String sItemList;
+            ItemStack[] items;
+            ItemStack offHand = new ItemStack(Material.AIR, 1);
+            ItemStack[] armors = new ItemStack[]{new ItemStack(Material.AIR, 1)};
 
             try {
-                sItemList = (String) stringObjectEntry1.getValue();
+                items = getItemStacksFromConfig(config.getList("classitems."+stringObjectEntry1.getKey()+".items"));
+                offHand = getItemStacksFromConfig(config.getList("classitems."+stringObjectEntry1.getKey()+".offhand"))[0];
+                armors = getItemStacksFromConfig(config.getList("classitems."+stringObjectEntry1.getKey()+".armor"));
             } catch (final Exception e) {
                 Bukkit.getLogger().severe(
                         "[PVP Arena] Error while parsing class, skipping: "
                                 + stringObjectEntry1.getKey());
+                        arena.getDebugger().i(e.getMessage());
                 continue;
             }
             try {
@@ -201,56 +218,23 @@ public static boolean configParse(final Arena arena, final Config cfg) {
                 PABlockLocation loc = new PABlockLocation(classChest);
                 Chest c = (Chest) loc.toLocation().getBlock().getState();
                 ItemStack[] contents = c.getInventory().getContents();
-                final ItemStack[] items = Arrays.copyOfRange(contents, 0, contents.length - 5);
-                final ItemStack offHand = contents[contents.length - 5];
-                final ItemStack[] armors = Arrays.copyOfRange(contents, contents.length - 4, contents.length);
+
+                items = Arrays.copyOfRange(contents, 0, contents.length - 5);
+                offHand = contents[contents.length - 5];
+                armors = Arrays.copyOfRange(contents, contents.length - 4, contents.length);
+
                 arena.addClass(stringObjectEntry1.getKey(), items, offHand, armors);
                 arena.getDebugger().i("adding class chest items to class " + stringObjectEntry1.getKey());
 
             }   catch (Exception e) {
-                final String[] sItems = sItemList.split(",");
-                final ItemStack[] items = new ItemStack[sItems.length];
-                final ItemStack[] offHand = new ItemStack[1];
-                final ItemStack[] armors = new ItemStack[4];
-
-                for (int i = 0; i < sItems.length; i++) {
-
-                    if (sItems[i].contains(">>!<<")) {
-                        final String[] split = sItems[i].split(">>!<<");
-
-                        final int id = Integer.parseInt(split[0]);
-                        armors[id] = StringParser.getItemStackFromString(split[1]);
-
-                        if (armors[id] == null) {
-                            PVPArena.instance.getLogger().warning(
-                                    "unrecognized armor item: " + split[1]);
-                        }
-
-                        sItems[i] = "AIR";
-                    } else if (sItems[i].contains(">>O<<")) {
-                        final String[] split = sItems[i].split(">>O<<");
-
-                        final int id = Integer.parseInt(split[0]);
-                        offHand[id] = StringParser.getItemStackFromString(split[1]);
-
-                        if (offHand[id] == null) {
-                            PVPArena.instance.getLogger().warning(
-                                    "unrecognized offhand item: " + split[1]);
-                        }
-                        sItems[i] = "AIR";
-                    }
-
-                    items[i] = StringParser.getItemStackFromString(sItems[i]);
-                    if (items[i] == null) {
-                        PVPArena.instance.getLogger().warning(
-                                "unrecognized item: " + items[i]);
-                    }
-                }
-                arena.addClass(stringObjectEntry1.getKey(), items, offHand[0], armors);
+                arena.addClass(stringObjectEntry1.getKey(), items, offHand, armors);
                 arena.getDebugger().i("adding class items to class " + stringObjectEntry1.getKey());
             }
         }
-        arena.addClass("custom", StringParser.getItemStacksFromString("AIR"), StringParser.getItemStackFromString("AIR"), StringParser.getItemStacksFromString("AIR"));
+        arena.addClass("custom",
+                new ItemStack[]{new ItemStack(Material.AIR, 1)},
+                new ItemStack(Material.AIR, 1),
+                new ItemStack[]{new ItemStack(Material.AIR, 1)});
         arena.setOwner(cfg.getString(CFG.GENERAL_OWNER));
         arena.setLocked(!cfg.getBoolean(CFG.GENERAL_ENABLED));
         arena.setFree("free".equals(cfg.getString(CFG.GENERAL_TYPE)));
@@ -298,8 +282,8 @@ public static boolean configParse(final Arena arena, final Config cfg) {
                 .getValues(true);
 
         if (arena.isFreeForAll()) {
-            if (!arena.getArenaConfig().getBoolean(CFG.PERMS_TEAMKILL)) {
-                PVPArena.instance.getLogger().warning("Arena " + arena.getName() + " is running in NO-PVP mode! Make sure people can die! Ignore this if you're running infect!");
+            if (!arena.getArenaConfig().getBoolean(CFG.PERMS_TEAMKILL) && !arena.getArenaConfig().getStringList(CFG.LISTS_GOALS).contains("Infect")) {
+                PVPArena.instance.getLogger().warning("Arena " + arena.getName() + " is running in NO-PVP mode! Make sure people can die!");
             }
         } else {
             for (final Map.Entry stringObjectEntry : tempMap.entrySet()) {
@@ -376,221 +360,4 @@ public static String isSetup(final Arena arena) {
         }
         return null;
     }
-
-    private static void updateItemIDs(Config config, String... versions) {
-        final String version = config.getString(CFG.Z);
-        boolean saveNeeded = false;
-
-        for (String v : versions) {
-            if (version.equals(v)) {
-                if (updateItemID(config, CFG.READY_BLOCK, Material.IRON_BLOCK)) {
-                    saveNeeded = true;
-                }
-                if (updateItemID(config, CFG.GENERAL_WAND, Material.STICK)) {
-                    saveNeeded = true;
-                }
-                if (updateItemID(config, CFG.GOAL_BLOCKDESTROY_BLOCKTYPE, Material.IRON_BLOCK)) {
-                    saveNeeded = true;
-                }
-                if (updateItemID(config, CFG.GOAL_FLAGS_FLAGTYPE, Material.WOOL)) {
-                    saveNeeded = true;
-                }
-                if (updateItemID(config, CFG.MODULES_WALLS_MATERIAL, Material.SAND)) {
-                    saveNeeded = true;
-                }
-                if (replaceItemIDs(config, CFG.LISTS_WHITELIST)) {
-                    saveNeeded = true;
-                }
-                if (replaceItemIDs(config, CFG.LISTS_BLACKLIST)) {
-                    saveNeeded = true;
-                }
-                if (replaceClassDefinitions(config)) {
-                    saveNeeded = true;
-                }
-
-                final File classFile = new File(PVPArena.instance.getDataFolder(), "classes.yml");
-                final YamlConfiguration cfg = YamlConfiguration.loadConfiguration(classFile);
-                final Map classMap = new HashMap<>();
-                ConfigurationSection configurationSection = cfg.getConfigurationSection("classes");
-                if (configurationSection != null && replaceConfig(configurationSection, classMap)) {
-                    for (String key : classMap.keySet()) {
-                        configurationSection.set(key, classMap.get(key));
-                    }
-                    try {
-                        cfg.save(classFile);
-                    } catch (IOException e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        }
-
-        if (saveNeeded) {
-            config.save();
-        }
-    }
-
-    private static boolean replaceClassDefinitions(Config config) {
-        final Map classMap = new HashMap<>();
-        ConfigurationSection configurationSection = config.getYamlConfiguration().getConfigurationSection("classitems");
-        if (replaceConfig(configurationSection, classMap)) {
-            for (String key : classMap.keySet()) {
-                configurationSection.set(key, classMap.get(key));
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private static boolean replaceConfig(ConfigurationSection configurationSection, Map classMap) {
-        boolean needsUpdateResult = false;
-        for (String node : configurationSection.getKeys(true)) {
-            String definition = configurationSection.getString(node);
-            if (definition.contains(",")) {
-                String[] definitions = definition.split(",");
-                boolean needsUpdate = false;
-                for (int pos=0; pos>!<<")) {
-            return replaceItemDefinition(def, ">>!<<");
-        } else if (def.contains(">>O<<")) {
-            return replaceItemDefinition(def, ">>O<<");
-        }
-        return replaceItemDefinition(def);
-    }
-
-    @SuppressWarnings("deprecation")
-    private static String replaceItemDefinition(String definition) {
-        if (definition.contains("|")) {
-            String[] split = definition.split("\\|");
-            try {
-                Material material = Material.getMaterial(Integer.parseInt(split[0]));
-                split[0] = material.name();
-                return StringParser.joinArray(split, "|");
-            } catch (Exception e) {
-                return definition;
-            }
-        } else if (definition.contains("~")) {
-            String[] split = definition.split("~");
-            try {
-                Material material = Material.getMaterial(Integer.parseInt(split[0]));
-                split[0] = material.name();
-                return StringParser.joinArray(split, "~");
-            } catch (Exception e) {
-                return definition;
-            }
-        } else if (definition.contains(":")) {
-            String[] split = definition.split(":");
-            try {
-                Material material = Material.getMaterial(Integer.parseInt(split[0]));
-                split[0] = material.name();
-                return StringParser.joinArray(split, ":");
-            } catch (Exception e) {
-                return definition;
-            }
-        }
-        try {
-            Material material = Material.getMaterial(Integer.parseInt(definition));
-            return material.name();
-        } catch (Exception e) {
-            return definition;
-        }
-    }
-
-    private static String replaceItemDefinition(String definition, String separator) {
-        String[] split = definition.split(separator);
-        split[1] = replaceItemDefinition(split[1]);
-        return StringParser.joinArray(split, separator);
-    }
-
-    @SuppressWarnings("deprecation")
-    private static boolean replaceItemIDs(Config config, CFG node) {
-        boolean saveNeeded = false;
-        final List subNodes = Arrays.asList("break", "place");
-
-        for (String subNode : subNodes) {
-            final String path = node.getNode() + "." + subNode;
-
-            final List configEntries = config.getStringList(path, new ArrayList());
-
-            final List oldEntries = new ArrayList<>();
-            final List newEntries = new ArrayList<>();
-
-            for (String entry : configEntries) {
-                if (entry.matches("[0-9]+")) {
-                    int id = Integer.parseInt(entry);
-                    Material material = Material.getMaterial(id);
-                    oldEntries.add(entry);
-                    newEntries.add(material.name());
-                } else if (entry.contains(":")){
-                    String first = entry.split(":")[0];
-                    if (first.matches("[0-9]+")) {
-                        int id = Integer.parseInt(first);
-                        Material material = Material.getMaterial(id);
-                        oldEntries.add(entry);
-                        newEntries.add(material.name()+entry.substring(entry.length()));
-                    }
-                }
-            }
-            if (!oldEntries.isEmpty()) {
-                for (int pos=0; pos drop(final Player player) {
                     exclude.add(item.getType());
                 }
             }
-            keepAll = ap.getArena().getArenaConfig().getString(CFG.ITEMS_KEEPONRESPAWN).equalsIgnoreCase("all");
+            keepAll = ap.getArena().getArenaConfig().getBoolean(CFG.ITEMS_KEEPALLONRESPAWN);
             if (keepAll) {
                 keep = new ArrayList<>();
             } else {
@@ -162,6 +162,5 @@ public static void transferItems(final Player player, final Inventory blockInven
                 }
             }
         }
-        player.updateInventory();
     }
 }
diff --git a/src/net/slipcor/pvparena/managers/SpawnManager.java b/src/net/slipcor/pvparena/managers/SpawnManager.java
index bed26950a..528cd1f09 100644
--- a/src/net/slipcor/pvparena/managers/SpawnManager.java
+++ b/src/net/slipcor/pvparena/managers/SpawnManager.java
@@ -137,13 +137,13 @@ public void run() {
                             int pos = new Random().nextInt(spawns.size());
                             for (final PASpawn spawn : spawns) {
                                 if (--pos < 0) {
-                                    arena.tpPlayerToCoordName(ap.get(), spawn.getName());
+                                    arena.tpPlayerToCoordName(ap, spawn.getName());
                                     break;
                                 }
                             }
 
                         } else {
-                            arena.tpPlayerToCoordName(ap.get(), locations[pos++ % locations.length].getName());
+                            arena.tpPlayerToCoordName(ap, locations[pos++ % locations.length].getName());
                         }
                         ap.setStatus(Status.FIGHT);
                         teamMembers.remove(ap);
@@ -210,14 +210,14 @@ public void run() {
                         int pos = new Random().nextInt(spawns.size());
                         for (final PASpawn spawn : spawns) {
                             if (--pos < 0) {
-                                arena.tpPlayerToCoordName(ap.get(), spawn.getName());
+                                arena.tpPlayerToCoordName(ap, spawn.getName());
                                 break;
                             }
                         }
 
                     } else {
                         for (final PASpawn s : spawns) {
-                            arena.tpPlayerToCoordName(ap.get(), s.getName());
+                            arena.tpPlayerToCoordName(ap, s.getName());
                             if (spawns.size() > 1) {
                                 spawns.remove(s);
                             }
@@ -307,7 +307,7 @@ public void run() {
                     if (spawnName == null) {
                         PVPArena.instance.getLogger().warning("Element #" + pos + " is null: [" + StringParser.joinArray(iteratings, ",") + ']');
                     }
-                    arena.tpPlayerToCoordName(ap.get(), spawnName);
+                    arena.tpPlayerToCoordName(ap, spawnName);
                     set.remove(ap);
                     return;
                 }
@@ -518,7 +518,7 @@ public void run() {
 
                 aPlayer.setStatus(Status.FIGHT);
 
-                arena.tpPlayerToCoordName(aPlayer.get(), "old");
+                arena.tpPlayerToCoordName(aPlayer, "old");
                 Bukkit.getScheduler().runTaskLater(PVPArena.instance, new Runnable() {
                             @Override
                             public void run() {
@@ -622,6 +622,9 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
             return;
         }
 
+        // Trick to avoid death screen
+        Bukkit.getScheduler().scheduleSyncDelayedTask(PVPArena.instance, () -> aPlayer.get().closeInventory(), 1);
+
         if (overrideSpawn == null) {
 
 
@@ -634,7 +637,7 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
                 int pos = new Random().nextInt(spawns.size());
                 for (final PASpawn spawn : spawns) {
                     if (--pos <= 0) {
-                        Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 1L);
+                        Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 2);
                         aPlayer.setStatus(Status.FIGHT);
                         return;
                     }
@@ -676,7 +679,7 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
                     int pos = new Random().nextInt(spawns.size());
                     for (final PASpawn spawn : spawns) {
                         if (--pos <= 0) {
-                            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 1L);
+                            Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 2);
                             aPlayer.setStatus(Status.FIGHT);
                             return;
                         }
@@ -723,7 +726,7 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
                     if (paLocationDoubleEntry.getValue() == max) {
                         for (final PASpawn spawn : spawns) {
                             if (spawn.getLocation().equals(paLocationDoubleEntry.getKey())) {
-                                Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 1L);
+                                Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 2);
                                 return;
                             }
                         }
@@ -738,7 +741,7 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
             int pos = new Random().nextInt(spawns.size());
             for (final PASpawn spawn : spawns) {
                 if (--pos <= 0) {
-                    Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 1L);
+                    Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, spawn.getName()), 2);
                     aPlayer.setStatus(Status.FIGHT);
                     return;
                 }
@@ -746,7 +749,7 @@ public static void respawn(final Arena arena, final ArenaPlayer aPlayer, final S
 
         }
 
-        Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, overrideSpawn), 1L);
+        Bukkit.getScheduler().runTaskLater(PVPArena.instance, new RespawnRunnable(arena, aPlayer, overrideSpawn), 2);
         if (overrideSpawn == null || !overrideSpawn.toLowerCase().endsWith("relay")) {
             aPlayer.setStatus(Status.FIGHT);
         }
diff --git a/src/net/slipcor/pvparena/managers/StatisticsManager.java b/src/net/slipcor/pvparena/managers/StatisticsManager.java
index bd26205db..60cfdd1be 100644
--- a/src/net/slipcor/pvparena/managers/StatisticsManager.java
+++ b/src/net/slipcor/pvparena/managers/StatisticsManager.java
@@ -11,14 +11,16 @@
 import net.slipcor.pvparena.events.PAKillEvent;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
-import org.bukkit.OfflinePlayer;
 import org.bukkit.configuration.file.YamlConfiguration;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Player;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.UUID;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.reverseOrder;
 
 /**
  * 
Statistics Manager class
@@ -31,12 +33,12 @@ public final class StatisticsManager { private static final Debug DEBUG = new Debug(28); - private static File players; + private static File playersFile; private static YamlConfiguration config; private StatisticsManager() {} - public enum type { + public enum Type { WINS("matches won", "Wins"), LOSSES("matches lost", "Losses"), KILLS("kills", "Kills"), @@ -50,9 +52,9 @@ public enum type { private final String fullName; private final String niceDesc; - type(final String name, final String desc) { - fullName = name; - niceDesc = desc; + Type(final String name, final String desc) { + this.fullName = name; + this.niceDesc = desc; } /** @@ -61,8 +63,8 @@ public enum type { * @param tType the type * @return the next type */ - public static type next(final type tType) { - final type[] types = type.values(); + public static Type next(final Type tType) { + final Type[] types = Type.values(); final int ord = tType.ordinal(); if (ord >= types.length - 2) { return types[0]; @@ -76,8 +78,8 @@ public static type next(final type tType) { * @param tType the type * @return the previous type */ - public static type last(final type tType) { - final type[] types = type.values(); + public static Type last(final Type tType) { + final Type[] types = Type.values(); final int ord = tType.ordinal(); if (ord <= 0) { return types[types.length - 2]; @@ -89,7 +91,7 @@ public static type last(final type tType) { * return the full stat name */ public String getName() { - return fullName; + return this.fullName; } /** @@ -98,8 +100,8 @@ public String getName() { * @param string the name to find * @return the type if found, null otherwise */ - public static type getByString(final String string) { - for (final type t : type.values()) { + public static Type getByString(final String string) { + for (final Type t : Type.values()) { if (t.name().equalsIgnoreCase(string)) { return t; } @@ -108,7 +110,7 @@ public static type getByString(final String string) { } public String getNiceName() { - return niceDesc; + return this.niceDesc; } } @@ -131,87 +133,63 @@ public static void damage(final Arena arena, final Entity entity, final Player d if (arena.hasPlayer(attacker)) { arena.getDebugger().i("attacker is in the arena, adding damage!", defender); final ArenaPlayer apAttacker = ArenaPlayer.parsePlayer(attacker.getName()); - final int maxdamage = apAttacker.getStatistics(arena).getStat(type.MAXDAMAGE); - apAttacker.getStatistics(arena).incStat(type.DAMAGE, (int) dmg); + final int maxdamage = apAttacker.getStatistics(arena).getStat(Type.MAXDAMAGE); + apAttacker.getStatistics(arena).incStat(Type.DAMAGE, (int) dmg); if (dmg > maxdamage) { - apAttacker.getStatistics(arena).setStat(type.MAXDAMAGE, (int) dmg); + apAttacker.getStatistics(arena).setStat(Type.MAXDAMAGE, (int) dmg); } } } final ArenaPlayer apDefender = ArenaPlayer.parsePlayer(defender.getName()); - final int maxdamage = apDefender.getStatistics(arena).getStat(type.MAXDAMAGETAKE); - apDefender.getStatistics(arena).incStat(type.DAMAGETAKE, (int) dmg); + final int maxdamage = apDefender.getStatistics(arena).getStat(Type.MAXDAMAGETAKE); + apDefender.getStatistics(arena).incStat(Type.DAMAGETAKE, (int) dmg); if (dmg > maxdamage) { - apDefender.getStatistics(arena).setStat(type.MAXDAMAGETAKE, (int) dmg); + apDefender.getStatistics(arena).setStat(Type.MAXDAMAGETAKE, (int) dmg); } } /** - * decide if a pair has to be sorted + * get an array of stats for arena boards and with a given stats type * - * @param aps the ArenaPlayer array - * @param pos the position to check - * @param sortBy the type to sort by - * @param desc descending order? - * @param global should we read global stats instead of arena stats? - * @return true if pair has to be sorted, false otherwise + * @param arena the arena to check + * @param statType the type to sort + * @return an array of stats values */ - private static boolean decide(final ArenaPlayer[] aps, final int pos, final type sortBy, - final boolean desc, final boolean global) { + public static String[] getStatsValuesForBoard(final Arena arena, final Type statType) { + DEBUG.i("getting stats values: " + (arena == null ? "global" : arena.getName()) + " sorted by " + statType); - int iThis = aps[pos].getStatistics(aps[pos].getArena()).getStat(sortBy); - int iNext = aps[pos + 1].getStatistics(aps[pos].getArena()).getStat(sortBy); - - if (global) { - iThis = aps[pos].getTotalStatistics(sortBy); - iNext = aps[pos + 1].getTotalStatistics(sortBy); + if (arena == null) { + return ArenaPlayer.getAllArenaPlayers().stream() + .map(ap -> (statType == Type.NULL) ? ap.getName() : String.valueOf(ap.getTotalStatistics(statType))) + .sorted(reverseOrder()) + .limit(8) + .toArray(String[]::new); } - return desc ? iThis < iNext : iThis > iNext; + return arena.getFighters().stream() + .map(ap -> (statType == Type.NULL) ? ap.getName() : String.valueOf(ap.getStatistics().getStat(statType))) + .sorted(reverseOrder()) + .limit(8) + .toArray(String[]::new); } /** - * get a set of arena players sorted by type - * - * @param arena the arena to check - * @param sortBy the type to sort - * @return an array of ArenaPlayer + * Get stats map for a given stat type + * @param arena the arena to check + * @param statType the kind of stat + * @return A map with player name and stat value */ - public static ArenaPlayer[] getStats(final Arena arena, final type sortBy) { - return getStats(arena, sortBy, true); - } - - /** - * get a set of arena players sorted by type - * - * @param arena the arena to check - * @param sortBy the type to sort - * @param desc should it be sorted descending? - * @return an array of ArenaPlayer - */ - private static ArenaPlayer[] getStats(final Arena arena, final type sortBy, final boolean desc) { - DEBUG.i("getting stats: " + (arena == null ? "global" : arena.getName()) + " sorted by " + sortBy + ' ' - + (desc ? "desc" : "asc")); - - final int count = arena == null ? ArenaPlayer.countPlayers() : arena.getFighters().size(); + public static Map getStats(final Arena arena, final Type statType) { + DEBUG.i("getting stats: " + (arena == null ? "global" : arena.getName()) + " sorted by " + statType); - final ArenaPlayer[] aps = new ArenaPlayer[count]; - - int pos = 0; if (arena == null) { - for (final ArenaPlayer p : ArenaPlayer.getAllArenaPlayers()) { - aps[pos++] = p; - } - } else { - for (final ArenaPlayer p : arena.getFighters()) { - aps[pos++] = p; - } + return ArenaPlayer.getAllArenaPlayers().stream() + .collect(Collectors.toMap(ArenaPlayer::getName, ap -> ap.getTotalStatistics(statType))); } - sortBy(aps, sortBy, desc, arena == null); - - return aps; + return arena.getFighters().stream() + .collect(Collectors.toMap(ArenaPlayer::getName, ap -> ap.getStatistics().getStat(statType))); } /** @@ -220,10 +198,10 @@ private static ArenaPlayer[] getStats(final Arena arena, final type sortBy, fina * @param line the line to determine the type * @return the Statistics type */ - public static type getTypeBySignLine(final String line) { + public static Type getTypeBySignLine(final String line) { final String stripped = ChatColor.stripColor(line).replace("[PA]", "").toUpperCase(); - for (final type t : type.values()) { + for (final Type t : Type.values()) { if (t.name().equals(stripped)) { return t; } @@ -231,7 +209,7 @@ public static type getTypeBySignLine(final String line) { return t; } } - return type.NULL; + return Type.NULL; } public static void initialize() { @@ -239,10 +217,10 @@ public static void initialize() { return; } config = new YamlConfiguration(); - players = new File(PVPArena.instance.getDataFolder(), "players.yml"); - if (!players.exists()) { + playersFile = new File(PVPArena.instance.getDataFolder(), "players.yml"); + if (!playersFile.exists()) { try { - players.createNewFile(); + playersFile.createNewFile(); Arena.pmsg(Bukkit.getConsoleSender(), Language.parse(MSG.STATS_FILE_DONE)); } catch (final Exception e) { Arena.pmsg(Bukkit.getConsoleSender(), Language.parse(MSG.ERROR_STATS_FILE)); @@ -251,7 +229,7 @@ public static void initialize() { } try { - config.load(players); + config.load(playersFile); } catch (final Exception e) { Arena.pmsg(Bukkit.getConsoleSender(), Language.parse(MSG.ERROR_STATS_FILE)); e.printStackTrace(); @@ -282,79 +260,17 @@ public static void kill(final Arena arena, final Entity entity, final Player def ArenaPlayer.parsePlayer(defender.getName()).addDeath(); } - /** - * gather all type information of an array of ArenaPlayers - * - * @param players the ArenaPlayer array to check - * @param tType the type to read - * @return an Array of String - */ - public static String[] read(final ArenaPlayer[] players, final type tType, final boolean global) { - final String[] result = new String[players.length < 8 ? 8 : players.length]; - int pos = 0; - if (global) { - for (final ArenaPlayer p : players) { - if (p == null) { - continue; - } - if (tType == type.NULL) { - result[pos++] = p.getName(); - } else { - result[pos++] = String.valueOf(p.getTotalStatistics(tType)); - } - } - } else { - for (final ArenaPlayer p : players) { - if (tType == type.NULL) { - result[pos++] = p.getName(); - } else { - result[pos++] = String.valueOf(p.getStatistics(p.getArena()).getStat(tType)); - } - } - } - while (pos < 8) { - result[pos++] = ""; - } - return result; - } - public static void save() { if (config == null) { return; } try { - config.save(players); + config.save(playersFile); } catch (final IOException e) { e.printStackTrace(); } } - /** - * bubble sort an ArenaPlayer array by type - * - * @param aps the ArenaPlayer array - * @param sortBy the type to sort by - * @param desc descending order? - * @param global announce to the whole server? - */ - private static void sortBy(final ArenaPlayer[] aps, final type sortBy, final boolean desc, final boolean global) { - int pos = aps.length; - boolean doMore = true; - while (doMore) { - pos--; - doMore = false; // assume this is our last pass over the array - for (int i = 0; i < pos; i++) { - if (decide(aps, i, sortBy, desc, global)) { - // exchange elements - final ArenaPlayer temp = aps[i]; - aps[i] = aps[i + 1]; - aps[i + 1] = temp; - doMore = true; // after an exchange, must look again - } - } - } - } - public static void loadStatistics(final Arena arena) { if (!PVPArena.instance.getConfig().getBoolean("stats")) { return; @@ -371,65 +287,55 @@ public static void loadStatistics(final Arena arena) { for (final String playerID : config.getConfigurationSection(arena.getName()).getKeys(false)) { - String player = playerID; - - if (config.getConfigurationSection(arena.getName()).contains(playerID+".playerName")) { - // old broken version - final OfflinePlayer oPlayer; - try { - oPlayer = Bukkit.getOfflinePlayer(UUID.fromString(playerID)); - } catch (final NoSuchMethodError error) { - continue; - } - - player = oPlayer.getName(); - config.getConfigurationSection(arena.getName()).set(playerID+".name", player); - config.getConfigurationSection(arena.getName()).set(playerID+".playerName", null); + String playerName = null; - foundBroken = true; - } else if (config.getConfigurationSection(arena.getName()).contains(playerID+".name")) { - // new version - player = config.getConfigurationSection(arena.getName()).getString(playerID+".name"); + if (config.getConfigurationSection(arena.getName()).contains(playerID+".name")) { + playerName = config.getConfigurationSection(arena.getName()).getString(playerID+".name"); } - arena.getDebugger().i("loading stats: " + player); + arena.getDebugger().i("loading stats: " + playerName); final ArenaPlayer aPlayer; try { - aPlayer = ArenaPlayer.parsePlayer(player); + if(playerName != null) { + aPlayer = ArenaPlayer.addPlayer(playerName); + } else { + continue; + } + } catch (IllegalArgumentException e) { PVPArena.instance.getLogger().warning("invalid player ID: " + playerID); continue; } - for (final type ttt : type.values()) { + for (final Type ttt : Type.values()) { aPlayer.setStatistic(arena.getName(), ttt, 0); } final int losses = config.getInt(arena.getName() + '.' + playerID + ".losses", 0); - aPlayer.addStatistic(arena.getName(), type.LOSSES, losses); + aPlayer.addStatistic(arena.getName(), Type.LOSSES, losses); final int wins = config.getInt(arena.getName() + '.' + playerID + ".wins", 0); - aPlayer.addStatistic(arena.getName(), type.WINS, wins); + aPlayer.addStatistic(arena.getName(), Type.WINS, wins); final int kills = config.getInt(arena.getName() + '.' + playerID + ".kills", 0); - aPlayer.addStatistic(arena.getName(), type.KILLS, kills); + aPlayer.addStatistic(arena.getName(), Type.KILLS, kills); final int deaths = config.getInt(arena.getName() + '.' + playerID + ".deaths", 0); - aPlayer.addStatistic(arena.getName(), type.DEATHS, deaths); + aPlayer.addStatistic(arena.getName(), Type.DEATHS, deaths); final int damage = config.getInt(arena.getName() + '.' + playerID + ".damage", 0); - aPlayer.addStatistic(arena.getName(), type.DAMAGE, damage); + aPlayer.addStatistic(arena.getName(), Type.DAMAGE, damage); final int maxdamage = config.getInt(arena.getName() + '.' + playerID + ".maxdamage", 0); - aPlayer.addStatistic(arena.getName(), type.MAXDAMAGE, maxdamage); + aPlayer.addStatistic(arena.getName(), Type.MAXDAMAGE, maxdamage); final int damagetake = config.getInt(arena.getName() + '.' + playerID + ".damagetake", 0); - aPlayer.addStatistic(arena.getName(), type.DAMAGETAKE, damagetake); + aPlayer.addStatistic(arena.getName(), Type.DAMAGETAKE, damagetake); final int maxdamagetake = config.getInt(arena.getName() + '.' + playerID + ".maxdamagetake", 0); - aPlayer.addStatistic(arena.getName(), type.MAXDAMAGETAKE, maxdamagetake); + aPlayer.addStatistic(arena.getName(), Type.MAXDAMAGETAKE, maxdamagetake); } if (foundBroken) { save(); @@ -447,32 +353,32 @@ public static void update(final Arena arena, final ArenaPlayer aPlayer) { try { node = aPlayer.get().getUniqueId().toString(); - } catch (final Exception e) { + } catch (final Exception ignored) { } - final int losses = map.getStat(type.LOSSES); + final int losses = map.getStat(Type.LOSSES); config.set(arena.getName() + '.' + node + ".losses", losses); - final int wins = map.getStat(type.WINS); + final int wins = map.getStat(Type.WINS); config.set(arena.getName() + '.' + node + ".wins", wins); - final int kills = map.getStat(type.KILLS); + final int kills = map.getStat(Type.KILLS); config.set(arena.getName() + '.' + node + ".kills", kills); - final int deaths = map.getStat(type.DEATHS); + final int deaths = map.getStat(Type.DEATHS); config.set(arena.getName() + '.' + node + ".deaths", deaths); - final int damage = map.getStat(type.DAMAGE); + final int damage = map.getStat(Type.DAMAGE); config.set(arena.getName() + '.' + node + ".damage", damage); - final int maxdamage = map.getStat(type.MAXDAMAGE); + final int maxdamage = map.getStat(Type.MAXDAMAGE); config.set(arena.getName() + '.' + node + ".maxdamage", maxdamage); - final int damagetake = map.getStat(type.DAMAGETAKE); + final int damagetake = map.getStat(Type.DAMAGETAKE); config.set(arena.getName() + '.' + node + ".damagetake", damagetake); - final int maxdamagetake = map.getStat(type.MAXDAMAGETAKE); + final int maxdamagetake = map.getStat(Type.MAXDAMAGETAKE); config.set(arena.getName() + '.' + node + ".maxdamagetake", maxdamagetake); if (!node.equals(aPlayer.getName())) { diff --git a/src/net/slipcor/pvparena/managers/TabManager.java b/src/net/slipcor/pvparena/managers/TabManager.java index 32df6c243..3bab4489a 100644 --- a/src/net/slipcor/pvparena/managers/TabManager.java +++ b/src/net/slipcor/pvparena/managers/TabManager.java @@ -7,7 +7,7 @@ import net.slipcor.pvparena.commands.AbstractArenaCommand; import net.slipcor.pvparena.commands.AbstractGlobalCommand; import net.slipcor.pvparena.commands.CommandTree; -import net.slipcor.pvparena.core.Language; +import net.slipcor.pvparena.commands.PAA_Edit; import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.loadables.ArenaRegion; import org.bukkit.Bukkit; @@ -18,29 +18,35 @@ import org.bukkit.potion.PotionEffectType; import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.bukkit.util.StringUtil.startsWithIgnoreCase; public final class TabManager { private TabManager() {} public static List getMatches(final CommandSender sender, final List arenaCommands, final List globalCommands, String[] args) { final Set matches = new LinkedHashSet<>(); + final String firstArg = args[0]; Arena arena = null; if (sender instanceof Player) { - arena = ArenaPlayer.parsePlayer(sender.getName()).getArena(); - } - - if (args.length < 1) { - for (final Arena a : ArenaManager.getArenas()) { - matches.add(a.getName()); + if (PAA_Edit.activeEdits.containsKey(sender.getName())){ + arena = PAA_Edit.activeEdits.get(sender.getName()); + } else { + arena = ArenaPlayer.parsePlayer(sender.getName()).getArena(); } - return new ArrayList<>(matches); } if (arena == null) { - // no proper arena yet - arena = ArenaManager.getArenaByName(args[0]); + // player is not inside an arena or in edit mode + + arena = ArenaManager.getArenaByExactName(firstArg); + if (arena == null && ArenaManager.getArenas().size() == 1) { - // still no arena, get the only arena! + // still no arena, get the only arena + arena = ArenaManager.getFirst(); // continue with one arg less args = Arrays.copyOfRange(args, 1, args.length); @@ -48,37 +54,36 @@ public static List getMatches(final CommandSender sender, final List turn to catchall args = new String[]{""}; } + } else if (arena != null) { - // arena has been found + // first argument matches with an arena + if (args.length < 2) { // return the exact arena name - matches.add(arena.getName()); - return new ArrayList<>(matches); + return singletonList(arena.getName()); } else { - // we have more args! + // if more args, we remove the first one (arena name) args = Arrays.copyOfRange(args, 1, args.length); if (args.length < 1) { // empty -> turn to catchall args = new String[]{""}; } } - } else { - // arena has still not been found - if (args.length > 1) { - // the sender has already entered the next thing without a valid arena - sender.sendMessage(Language.parse(Language.MSG.ERROR_ARENA_NOTFOUND, args[0])); - return new ArrayList<>(matches); - } - for (final Arena a : ArenaManager.getArenas()) { - matches.add(a.getName()); - } + } else if(args.length == 1) { + // else, if only one arg, suggest arena names and global commands + + matches.addAll(ArenaManager.getArenas().stream() + .filter(a -> startsWithIgnoreCase(a.getName(), firstArg)) + .map(Arena::getName) + .collect(Collectors.toList())); + + addCommandsStartingWithPrefix(matches, sender, arena, globalCommands, firstArg); return new ArrayList<>(matches); } } if (args.length == 1) { addCommandsStartingWithPrefix(matches, sender, arena, arenaCommands, args[0]); - addCommandsStartingWithPrefix(matches, sender, arena, globalCommands, args[0]); if (arena == null) { addCommandsStartingWithPrefix(matches, sender, null, PVPArena.instance.getAgm().getAllGoals(), args[0]); @@ -117,14 +122,17 @@ public static List getMatches(final CommandSender sender, final List matches, final CommandSender sender, final Arena arena, final List list, final String prefix) { for (final IArenaCommandHandler ach : list) { if (ach.hasPerms(sender, arena)) { - for (final String value : ach.getMain()) { - if (value.startsWith(prefix)) { - matches.add(value); + if(prefix.startsWith("!") || prefix.startsWith("-")) { + for (final String value : ach.getShort()) { + if (startsWithIgnoreCase(value, prefix)) { + matches.add(value); + } } - } - for (final String value : ach.getShort()) { - if (value.startsWith(prefix)) { - matches.add(value); + } else { + for (final String value : ach.getMain()) { + if (startsWithIgnoreCase(value, prefix)) { + matches.add(value); + } } } } @@ -140,7 +148,7 @@ private static void addCommandsStartingWithPrefix(final Set matches, fin */ private static void addEnumMatchesToList(final List result, final String key, final List list) { for (final Enum e : list) { - if (e.name().startsWith(key)) { + if (startsWithIgnoreCase(e.name(), key)) { result.add(e.name()); } } @@ -220,13 +228,13 @@ private static void addTreesMatchingValueInHandlerList(final List getKeyMatchesInsideDefinition(final String key, final String definition) { final List result = new ArrayList<>(); - if (key != null && !key.isEmpty() && definition.startsWith(key) || key != null && key.isEmpty() && !definition.startsWith("{")) { + if (key != null && (!key.isEmpty() && startsWithIgnoreCase(definition, key) || key.isEmpty() && !definition.startsWith("{"))) { result.add(definition); } if (definition.startsWith("{")) { if ("{Material}".equals(definition)) { final Material[] mats = Material.values(); - addEnumMatchesToList(result, key, Arrays.asList(mats)); + addEnumMatchesToList(result, key, asList(mats)); } else if ("{Player}".equals(definition)) { final Collection players = Bukkit.getOnlinePlayers(); if (key != null && key.isEmpty()) { @@ -235,20 +243,20 @@ private static List getKeyMatchesInsideDefinition(final String key, fina } } else if (key != null) { for (final Player val : players) { - if (val.getName().startsWith(key)) { + if (startsWithIgnoreCase(val.getName(), key)) { result.add(val.getName()); } } } } else if ("{RegionProtection}".equals(definition)) { final ArenaRegion.RegionProtection[] protections = ArenaRegion.RegionProtection.values(); - addEnumMatchesToList(result, key, Arrays.asList(protections)); + addEnumMatchesToList(result, key, asList(protections)); } else if ("{RegionFlag}".equals(definition)) { final ArenaRegion.RegionFlag[] flags = ArenaRegion.RegionFlag.values(); - addEnumMatchesToList(result, key, Arrays.asList(flags)); + addEnumMatchesToList(result, key, asList(flags)); } else if ("{RegionType}".equals(definition)) { final ArenaRegion.RegionType[] types = ArenaRegion.RegionType.values(); - addEnumMatchesToList(result, key, Arrays.asList(types)); + addEnumMatchesToList(result, key, asList(types)); } else if ("{Boolean}".equals(definition)) { final List values = new ArrayList<>(); values.addAll(StringParser.negative); @@ -257,7 +265,7 @@ private static List getKeyMatchesInsideDefinition(final String key, fina result.addAll(values); } else if (key != null) { for (final String val : values) { - if (val.startsWith(key)) { + if (startsWithIgnoreCase(val, key)) { result.add(val); } } @@ -270,14 +278,14 @@ private static List getKeyMatchesInsideDefinition(final String key, fina } } else if (key != null) { for (final PotionEffectType val : pet) { - if (val.getName().startsWith(key)) { + if (startsWithIgnoreCase(val.getName(), key)) { result.add(val.getName()); } } } } else if ("{EntityType}".equals(definition)) { final EntityType[] entityTypes = EntityType.values(); - addEnumMatchesToList(result, key, Arrays.asList(entityTypes)); + addEnumMatchesToList(result, key, asList(entityTypes)); } } return result; @@ -294,7 +302,7 @@ private static String getOverrideFromDefinition(final String key, final String d if (definition.startsWith("{")) { if ("{Material}".equals(definition)) { final Material[] mats = Material.values(); - return getOverrideKey(key, definition, Arrays.asList(mats)); + return getOverrideKey(key, definition, asList(mats)); } else if ("{String}".equals(definition)) { return definition; } else if ("{Player}".equals(definition)) { @@ -307,13 +315,13 @@ private static String getOverrideFromDefinition(final String key, final String d return key; } else if ("{RegionProtection}".equals(definition)) { final ArenaRegion.RegionProtection[] protections = ArenaRegion.RegionProtection.values(); - return getOverrideKey(key, definition, Arrays.asList(protections)); + return getOverrideKey(key, definition, asList(protections)); } else if ("{RegionFlag}".equals(definition)) { final ArenaRegion.RegionFlag[] flags = ArenaRegion.RegionFlag.values(); - return getOverrideKey(key, definition, Arrays.asList(flags)); + return getOverrideKey(key, definition, asList(flags)); } else if ("{RegionType}".equals(definition)) { final ArenaRegion.RegionType[] types = ArenaRegion.RegionType.values(); - return getOverrideKey(key, definition, Arrays.asList(types)); + return getOverrideKey(key, definition, asList(types)); } else if ("{Boolean}".equals(definition)) { final List values = new ArrayList<>(); values.addAll(StringParser.negative); @@ -342,7 +350,7 @@ private static String getOverrideFromDefinition(final String key, final String d return key; } else if ("{EntityType}".equals(definition)) { final EntityType[] entityTypes = EntityType.values(); - return getOverrideKey(key, definition, Arrays.asList(entityTypes)); + return getOverrideKey(key, definition, asList(entityTypes)); } } return key; diff --git a/src/net/slipcor/pvparena/modules/BattlefieldJoin.java b/src/net/slipcor/pvparena/modules/BattlefieldJoin.java index 2481fdbf6..dc342c798 100644 --- a/src/net/slipcor/pvparena/modules/BattlefieldJoin.java +++ b/src/net/slipcor/pvparena/modules/BattlefieldJoin.java @@ -113,7 +113,7 @@ public void commitJoin(final Player sender, final ArenaTeam team) { for (final PASpawn spawn : spawns) { if (--pos < 0) { - arena.tpPlayerToCoordName(player.get(), spawn.getName()); + this.arena.tpPlayerToCoordNameForJoin(player, spawn.getName(), true); break; } } diff --git a/src/net/slipcor/pvparena/modules/RegionTool.java b/src/net/slipcor/pvparena/modules/RegionTool.java index c5e872688..cef900fe5 100644 --- a/src/net/slipcor/pvparena/modules/RegionTool.java +++ b/src/net/slipcor/pvparena/modules/RegionTool.java @@ -5,12 +5,9 @@ import net.slipcor.pvparena.classes.PABlockLocation; import net.slipcor.pvparena.core.Config.CFG; import net.slipcor.pvparena.core.Debug; -import net.slipcor.pvparena.core.Language; -import net.slipcor.pvparena.core.Language.MSG; import net.slipcor.pvparena.loadables.ArenaModule; import net.slipcor.pvparena.loadables.ArenaRegion; import net.slipcor.pvparena.managers.ArenaManager; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.event.player.PlayerInteractEvent; diff --git a/src/net/slipcor/pvparena/modules/StandardLounge.java b/src/net/slipcor/pvparena/modules/StandardLounge.java index c9c78870c..f6d77e668 100644 --- a/src/net/slipcor/pvparena/modules/StandardLounge.java +++ b/src/net/slipcor/pvparena/modules/StandardLounge.java @@ -175,13 +175,13 @@ public void commitJoin(final Player sender, final ArenaTeam team) { player.setLocation(new PALocation(player.get().getLocation())); // ArenaPlayer.prepareInventory(arena, ap.get()); - player.setArena(arena); + player.setArena(this.arena); team.add(player); - if (arena.isFreeForAll()) { - arena.tpPlayerToCoordName(player.get(), "lounge"); + if (this.arena.isFreeForAll()) { + this.arena.tpPlayerToCoordNameForJoin(player, "lounge", true); } else { - arena.tpPlayerToCoordName(player.get(), team.getName() + "lounge"); + this.arena.tpPlayerToCoordNameForJoin(player, team.getName() + "lounge", true); } player.setStatus(Status.LOUNGE); diff --git a/src/net/slipcor/pvparena/modules/StandardSpectate.java b/src/net/slipcor/pvparena/modules/StandardSpectate.java index 878261303..746e3a73e 100644 --- a/src/net/slipcor/pvparena/modules/StandardSpectate.java +++ b/src/net/slipcor/pvparena/modules/StandardSpectate.java @@ -68,11 +68,11 @@ public void commitSpectate(final Player player) { final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName()); aPlayer.setLocation(new PALocation(player.getLocation())); - aPlayer.setArena(arena); + aPlayer.setArena(this.arena); aPlayer.setStatus(Status.WATCH); - arena.tpPlayerToCoordName(player, "spectator"); - arena.msg(player, Language.parse(arena, MSG.NOTICE_WELCOME_SPECTATOR)); + this.arena.tpPlayerToCoordNameForJoin(aPlayer, "spectator", true); + this.arena.msg(player, Language.parse(this.arena, MSG.NOTICE_WELCOME_SPECTATOR)); if (aPlayer.getState() == null) { diff --git a/src/net/slipcor/pvparena/regions/CuboidRegion.java b/src/net/slipcor/pvparena/regions/CuboidRegion.java index 1203615bb..03584bb69 100644 --- a/src/net/slipcor/pvparena/regions/CuboidRegion.java +++ b/src/net/slipcor/pvparena/regions/CuboidRegion.java @@ -213,7 +213,7 @@ public void showBorder(final Player player) { for (final Block b : border) { if (!region.isInNoWoolSet(b)) { - player.sendBlockChange(b.getLocation(), Material.WOOL, (byte) 0); + player.sendBlockChange(b.getLocation(), Material.WHITE_WOOL.createBlockData()); } } @@ -224,7 +224,7 @@ public void showBorder(final Player player) { public void run() { for (final Block b : border) { player.sendBlockChange(b.getLocation(), - b.getType(), b.getData()); + b.getType().createBlockData()); } border.clear(); } diff --git a/src/net/slipcor/pvparena/regions/CylindricRegion.java b/src/net/slipcor/pvparena/regions/CylindricRegion.java index 1349d46f0..19b2bf6f6 100644 --- a/src/net/slipcor/pvparena/regions/CylindricRegion.java +++ b/src/net/slipcor/pvparena/regions/CylindricRegion.java @@ -255,7 +255,7 @@ public void showBorder(final Player player) { for (final Block b : border) { if (!region.isInNoWoolSet(b)) { - player.sendBlockChange(b.getLocation(), Material.WOOL, (byte) 0); + player.sendBlockChange(b.getLocation(), Material.WHITE_WOOL.createBlockData()); } } @@ -266,7 +266,7 @@ public void showBorder(final Player player) { public void run() { for (final Block b : border) { player.sendBlockChange(b.getLocation(), - b.getType(), b.getData()); + b.getType().createBlockData()); } border.clear(); } diff --git a/src/net/slipcor/pvparena/regions/SphericRegion.java b/src/net/slipcor/pvparena/regions/SphericRegion.java index 5bee27392..d38220ed4 100644 --- a/src/net/slipcor/pvparena/regions/SphericRegion.java +++ b/src/net/slipcor/pvparena/regions/SphericRegion.java @@ -262,7 +262,7 @@ public void showBorder(final Player player) { for (final Block b : border) { if (!region.isInNoWoolSet(b)) { - player.sendBlockChange(b.getLocation(), Material.WOOL, (byte) 0); + player.sendBlockChange(b.getLocation(), Material.WHITE_WOOL.createBlockData()); } } @@ -273,7 +273,7 @@ public void showBorder(final Player player) { public void run() { for (final Block b : border) { player.sendBlockChange(b.getLocation(), - b.getType(), b.getData()); + b.getType().createBlockData()); } border.clear(); } diff --git a/src/net/slipcor/pvparena/runnables/CircleParticleRunnable.java b/src/net/slipcor/pvparena/runnables/CircleParticleRunnable.java index 81bd44d1d..aa604c6ea 100644 --- a/src/net/slipcor/pvparena/runnables/CircleParticleRunnable.java +++ b/src/net/slipcor/pvparena/runnables/CircleParticleRunnable.java @@ -2,43 +2,60 @@ import net.slipcor.pvparena.arena.Arena; import net.slipcor.pvparena.classes.PABlock; +import net.slipcor.pvparena.core.ColorUtils; import net.slipcor.pvparena.core.Config; -import org.bukkit.Bukkit; -import org.bukkit.Particle; +import net.slipcor.pvparena.core.Utils; +import org.bukkit.*; + +import java.util.Map; public class CircleParticleRunnable implements Runnable { - final Arena arena; - double radius = 3; - int i = 0; + private Map flagMap; + private final Arena arena; + private double radius; + private int i = 0; - public CircleParticleRunnable(Arena arena, Config.CFG config) { + public CircleParticleRunnable(Arena arena, Config.CFG config, Map flagMap) { this.arena = arena; - radius = arena.getArenaConfig().getInt(config, 3); + this.flagMap = flagMap; + this.radius = arena.getArenaConfig().getInt(config, 3); + } + + private Color getDustColor(Location flagLocation) { + if(this.flagMap.containsKey(flagLocation)) { + ChatColor teamColor = this.arena.getTeam(this.flagMap.get(flagLocation)).getColor(); + return ColorUtils.getDyeColorFromChatColor(teamColor).getColor(); + } + return Color.WHITE; } @Override public void run() { - for (PABlock spawn : arena.getBlocks()) { + for (PABlock spawn : this.arena.getBlocks()) { if (spawn.getName().startsWith("flag") || spawn.getName().startsWith("beacon")) { - final double x = spawn.getLocation().getX() + radius * Math.cos(Math.toRadians(i)); - final double y = spawn.getLocation().getY(); - final double z = spawn.getLocation().getZ() + radius * Math.sin(Math.toRadians(i)); + final Location flagCenter = Utils.getCenteredLocation(spawn.getLocation().toLocation()); + final double x = flagCenter.getX() + this.radius * Math.cos(Math.toRadians(this.i)); + final double y = flagCenter.getY(); + final double z = flagCenter.getZ() + this.radius * Math.sin(Math.toRadians(this.i)); + + final Color dustColor = this.getDustColor(spawn.getLocation().toLocation()); - Bukkit.getWorld(arena.getWorld()).spawnParticle( + Bukkit.getWorld(this.arena.getWorld()).spawnParticle( Particle.REDSTONE, x, y, z, 0, // count 1, 1, 1, // offsets (colors) - 1 // extra (lighting) + 1, // extra (lighting) + new Particle.DustOptions(dustColor, 1) ); } } - i += 10; + this.i += 10; - if (i >= 360) { - i = 0; + if (this.i >= 360) { + this.i = 0; } } } diff --git a/src/net/slipcor/pvparena/runnables/InventoryRefillRunnable.java b/src/net/slipcor/pvparena/runnables/InventoryRefillRunnable.java index b24c15b3c..bcf331cf4 100644 --- a/src/net/slipcor/pvparena/runnables/InventoryRefillRunnable.java +++ b/src/net/slipcor/pvparena/runnables/InventoryRefillRunnable.java @@ -6,11 +6,11 @@ import net.slipcor.pvparena.arena.ArenaPlayer; import net.slipcor.pvparena.arena.ArenaPlayer.Status; import net.slipcor.pvparena.arena.ArenaTeam; +import net.slipcor.pvparena.core.ColorUtils; import net.slipcor.pvparena.core.Config.CFG; -import net.slipcor.pvparena.core.StringParser; import net.slipcor.pvparena.managers.InventoryManager; import org.bukkit.Bukkit; -import org.bukkit.Material; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -42,10 +42,10 @@ public InventoryRefillRunnable(final Arena arena, final Player player, final Lis } this.arena = arena == null ? aPlayer.getArena() : arena; - boolean keepAll = "all".equalsIgnoreCase(this.arena.getArenaConfig().getString(CFG.ITEMS_KEEPONRESPAWN)); + boolean keepAll = this.arena.getArenaConfig().getBoolean(CFG.ITEMS_KEEPALLONRESPAWN); - if (!"none".equals(this.arena.getArenaConfig().getString(CFG.ITEMS_KEEPONRESPAWN))) { - final ItemStack[] items = StringParser.getItemStacksFromString(this.arena.getArenaConfig().getString(CFG.ITEMS_KEEPONRESPAWN)); + if (this.arena.getArenaConfig().getItems(CFG.ITEMS_KEEPONRESPAWN) != null) { + final ItemStack[] items = this.arena.getArenaConfig().getItems(CFG.ITEMS_KEEPONRESPAWN); for (final ItemStack item : itemList) { if (item != null) { @@ -59,10 +59,6 @@ public InventoryRefillRunnable(final Arena arena, final Player player, final Lis continue; } - if (item.getData().getData() != iItem.getData().getData()) { - continue; - } - additions.add(item); break; } @@ -82,32 +78,35 @@ public void run() { final ArenaPlayer aPlayer = ArenaPlayer.parsePlayer(player.getName()); arena.getDebugger().i("refilling " + player.getName()); if (aPlayer.getStatus() == Status.FIGHT) { - if ("custom".equals(aPlayer.getArenaClass().getName()) && !arena.getArenaConfig().getBoolean(CFG.PLAYER_REFILLCUSTOMINVENTORY) || !arena.getArenaConfig().getBoolean(CFG.PLAYER_REFILLINVENTORY)) { + if (aPlayer.hasCustomClass() && !arena.getArenaConfig().getBoolean(CFG.PLAYER_REFILLCUSTOMINVENTORY) || !arena.getArenaConfig().getBoolean(CFG.PLAYER_REFILLINVENTORY)) { if (refill) { final ItemStack[] items = new ItemStack[additions.size()]; int pos = 0; for (final ItemStack item : additions) { items[pos++] = item; } - ArenaClass.equip(player, items); + if(items.length > 0){ + ArenaClass.equip(player, items); + } else { + PVPArena.instance.getLogger().info("Can't refill inventory, please set " + CFG.ITEMS_KEEPONRESPAWN.getNode() + + ", " + CFG.ITEMS_KEEPALLONRESPAWN.getNode() + " or " + CFG.PLAYER_REFILLCUSTOMINVENTORY.getNode() + " parameter"); + } } if (arena.getArenaConfig().getBoolean(CFG.USES_WOOLHEAD)) { final ArenaTeam aTeam = aPlayer.getArenaTeam(); - final String color = aTeam.getColor().name(); + final ChatColor chatColor = aTeam.getColor(); arena.getDebugger().i("forcing woolhead: " + aTeam.getName() + '/' - + color, player); + + chatColor.name(), player); player.getInventory().setHelmet( - new ItemStack(Material.WOOL, 1, StringParser - .getColorDataFromENUM(color))); + new ItemStack(ColorUtils.getWoolMaterialFromChatColor(chatColor), 1)); PVPArena.instance.getAgm().refillInventory(arena, player); } - } else if (refill && "custom".equals(aPlayer.getArenaClass().getName())) { + } else if (refill && aPlayer.hasCustomClass()) { ArenaPlayer.reloadInventory(arena, player, false); for (final ItemStack item : additions) { player.getInventory().addItem(item); } - player.updateInventory(); } else if (refill) { InventoryManager.clearInventory(player); ArenaPlayer.givePlayerFightItems(arena, player); @@ -115,7 +114,6 @@ public void run() { for (final ItemStack item : additions) { player.getInventory().addItem(item); } - player.updateInventory(); } } else { arena.getDebugger().i("NOT"); diff --git a/src/net/slipcor/pvparena/runnables/RegionRunnable.java b/src/net/slipcor/pvparena/runnables/RegionRunnable.java index 974ab5b87..bfa68603d 100644 --- a/src/net/slipcor/pvparena/runnables/RegionRunnable.java +++ b/src/net/slipcor/pvparena/runnables/RegionRunnable.java @@ -3,6 +3,9 @@ import net.slipcor.pvparena.PVPArena; import net.slipcor.pvparena.loadables.ArenaRegion; import net.slipcor.pvparena.loadables.ArenaRegion.RegionType; +import org.bukkit.scheduler.BukkitRunnable; + +import static java.util.Arrays.asList; /** *
@@ -15,7 +18,7 @@
  * @version v0.9.9
  */
 
-public class RegionRunnable implements Runnable {
+public class RegionRunnable extends BukkitRunnable {
     private final ArenaRegion region;
 //	private final static Debug DEBUG = new Debug(49);
 //	private int iID;
@@ -74,8 +77,8 @@ public void run() {
                 region.getArena().getDebugger().i("tick 2: " + region.getRegionName());
                 region.tick();
             }
-        } else if (region.getType() == RegionType.WATCH) {
-            // always tick for WATCH regions!
+        } else if (asList(RegionType.WATCH, RegionType.LOUNGE).contains(region.getType())) {
+            // always tick for WATCH & LOUNGE regions!
             region.getArena().getDebugger().i("tick 3: " + region.getRegionName());
             region.tick();
         } else if (region.getArena().isFightInProgress()) {
diff --git a/src/net/slipcor/pvparena/runnables/RespawnRunnable.java b/src/net/slipcor/pvparena/runnables/RespawnRunnable.java
index 64d01b23e..5c4fa4f19 100644
--- a/src/net/slipcor/pvparena/runnables/RespawnRunnable.java
+++ b/src/net/slipcor/pvparena/runnables/RespawnRunnable.java
@@ -55,12 +55,12 @@ public void run() {
 
             for (final PASpawn spawn : spawns) {
                 if (--pos < 0) {
-                    arena.tpPlayerToCoordName(player.get(), spawn.getName());
+                    this.arena.tpPlayerToCoordName(player, spawn.getName());
                     break;
                 }
             }
         } else {
-            arena.tpPlayerToCoordName(player.get(), coordName);
+            this.arena.tpPlayerToCoordName(player, coordName);
         }
     }
 
diff --git a/src/net/slipcor/pvparena/updater/AbstractUpdater.java b/src/net/slipcor/pvparena/updater/AbstractUpdater.java
new file mode 100644
index 000000000..498a965fd
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/AbstractUpdater.java
@@ -0,0 +1,156 @@
+package net.slipcor.pvparena.updater;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import net.slipcor.pvparena.PVPArena;
+import net.slipcor.pvparena.core.Language;
+import net.slipcor.pvparena.core.Language.MSG;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * Abstract class with shared methods fo updaters
+ */
+public abstract class AbstractUpdater implements Runnable {
+    protected final UpdateMode updateMode;
+    protected List updateMsgList;
+    protected Runnable toRunOnDisable;
+    protected static final Logger LOG = PVPArena.instance.getLogger();
+
+    /**
+     * Constructs a AbstractUpdater instance
+     * @param updateMsgList Reference to UpdateChecker message list
+     * @param configNode YML config node to get update setting
+     */
+    public AbstractUpdater(List updateMsgList, String configNode) {
+        FileConfiguration config = PVPArena.instance.getConfig();
+        this.updateMode = UpdateMode.getBySetting(config.getString(configNode, UpdateMode.ANNOUNCE.name()));
+        this.updateMsgList = updateMsgList;
+    }
+
+    /**
+     * Runs an updater if it's not disabled
+     */
+    public void run() {
+        try {
+            if(this.updateMode != UpdateMode.OFF) {
+                runUpdater();
+            }
+        } catch (IOException e) {
+            LOG.warning("Unable to connect to api.github.com");
+        }
+    }
+
+    public void runOnDisable() {
+        if(this.toRunOnDisable != null) {
+            this.toRunOnDisable.run();
+        }
+    }
+
+    /**
+     * Runs  an updater implementation
+     * @throws IOException Exception if api.github.com is unreachable
+     */
+    protected abstract void runUpdater() throws IOException;
+
+    /**
+     * Returns release version from API json
+     * @param jsonObject API json
+     * @return version as string
+     */
+    protected static String getOnlineVersionFromJson(JsonObject jsonObject) {
+        String tagName = jsonObject.get("tag_name").getAsString();
+        return tagName.replace("v", "");
+    }
+
+    /**
+     * Returns release download URL from API json
+     * @param jsonObject API json
+     * @return download URL as string
+     */
+    protected static String getDownloadUrlFromJson(JsonObject jsonObject) {
+        JsonArray jsonArray = jsonObject.getAsJsonArray("assets");
+        JsonObject assetArray = jsonArray.get(0).getAsJsonObject();
+        return assetArray.get("browser_download_url").getAsString();
+    }
+
+    /**
+     * Returns release filename from API json
+     * @param jsonObject API json
+     * @return filename as string
+     */
+    protected static String getFilenameFromJson(JsonObject jsonObject) {
+        JsonArray jsonArray = jsonObject.getAsJsonArray("assets");
+        JsonObject assetArray = jsonArray.get(0).getAsJsonObject();
+        return assetArray.get("name").getAsString();
+    }
+
+    /**
+     * Returns a JsonObject view of Api result stream
+     * @param inputStream InputStream returned by Api connection
+     * @return JsonObject
+     * @throws IOException Exception on json parsing
+     */
+    protected static JsonObject getVersionJson(InputStream inputStream) throws IOException {
+        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
+        JsonElement jsonElement = new JsonParser().parse(in);
+        JsonObject jsonObject = jsonElement.getAsJsonObject();
+        in.close();
+        return jsonObject;
+    }
+
+    /**
+     * Returns announce message of new available update
+     * @param args Args for stringFormatter
+     * @return Announce message
+     */
+    protected static String getAnnounceMessage(String... args) {
+        return Language.parse(MSG.UPDATER_ANNOUNCE, args);
+    }
+
+    /**
+     * Returns update success message
+     * @param args Args for stringFormatter
+     * @return success message
+     */
+    protected static String getSuccessMessage(String... args) {
+        return Language.parse(MSG.UPDATER_SUCCESS, args);
+    }
+
+    /**
+     * Checks if current version is up to date
+     * @param currentVersion version currently installed as x.x.x format
+     * @param newVersion latest version available as x.x.x format
+     * @return true if current version is up to date, false otherwise
+     */
+    protected static boolean isUpToDate(String currentVersion, String newVersion) {
+        String[] fullCurrentVerArr = currentVersion.split("-");
+        boolean isSnapshot = currentVersion.contains("SNAPSHOT");
+        String[] currentVerArr = fullCurrentVerArr[0].split("\\.");
+        String[] newVerArr = newVersion.split("\\.");
+        int currentVerVal = 0;
+        int newVerVal = 0;
+
+        final int versionLen = 3;
+        for(int i = 0; i < versionLen; i++) {
+            Long currentVerChunk = Long.valueOf(currentVerArr[i]);
+            Long newVerChunk = Long.valueOf(newVerArr[i]);
+            currentVerVal += currentVerChunk * Math.pow(10, versionLen - i);
+            newVerVal += newVerChunk * Math.pow(10, versionLen - i);
+        }
+
+        if(currentVerVal == newVerVal) {
+            //Release > snapshot if there are the same number
+            return !isSnapshot;
+        }
+        return currentVerVal > newVerVal;
+    }
+}
diff --git a/src/net/slipcor/pvparena/updater/ModulesUpdater.java b/src/net/slipcor/pvparena/updater/ModulesUpdater.java
new file mode 100644
index 000000000..e684fc3c3
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/ModulesUpdater.java
@@ -0,0 +1,154 @@
+package net.slipcor.pvparena.updater;
+
+import com.google.gson.JsonObject;
+import net.slipcor.pvparena.PVPArena;
+import net.slipcor.pvparena.arena.Arena;
+import net.slipcor.pvparena.core.Language;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.List;
+
+import static net.slipcor.pvparena.core.Language.MSG;
+
+/**
+ * Manage modules versions and updates
+ */
+public class ModulesUpdater extends AbstractUpdater {
+
+    private final static String API_URL = "https://api.github.com/repos/Eredrim/pvparena_modules/releases/latest";
+    private static final String CONFIG_NODE = "update.modules";
+
+    /**
+     * Construct a modules updater
+     * @param msgList Reference to UpdateChecker message list
+     */
+    public ModulesUpdater(List msgList) {
+        super(msgList, CONFIG_NODE);
+    }
+
+    /**
+     * Run modules updaters : checks version and downloads update according to config
+     * @throws IOException Exception if can't connect to github API
+     */
+    protected void runUpdater() throws IOException {
+        String currentVersion = this.getModulesVersion();
+        URL githubApi = new URL(API_URL);
+        URLConnection connection = githubApi.openConnection();
+        JsonObject versionJson = getVersionJson(connection.getInputStream());
+        String onlineVersion = getOnlineVersionFromJson(versionJson);
+
+        if(currentVersion == null) {
+            LOG.info("PVP Arena modules are not detected");
+        } else if(isUpToDate(currentVersion, onlineVersion)) {
+            LOG.info("PVP Arena modules are up to date");
+        } else {
+            String updateInfo = getAnnounceMessage(MSG.UPDATER_MODULES.toString(), onlineVersion, currentVersion);
+            LOG.info(updateInfo);
+            if(this.updateMode == UpdateMode.ANNOUNCE) {
+                this.updateMsgList.add(updateInfo);
+            } else if(this.updateMode == UpdateMode.DOWNLOAD ) {
+                String filename = getFilenameFromJson(versionJson);
+                LOG.info("Downloading modules update...");
+                try {
+                    downloadAndUnpackModules(getDownloadUrlFromJson(versionJson), filename);
+                    String updateSuccess = getSuccessMessage(MSG.UPDATER_MODULES.toString(), onlineVersion);
+                    LOG.info(updateSuccess);
+                    this.updateMsgList.add(updateSuccess);
+                } catch (IOException e) {
+                    LOG.warning("Error during modules update");
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static void downloadModulePack(CommandSender sender) {
+        try {
+            URL githubApi = new URL(API_URL);
+            URLConnection connection = githubApi.openConnection();
+            JsonObject versionJson = getVersionJson(connection.getInputStream());
+            String onlineVersion = getOnlineVersionFromJson(versionJson);
+            String filename = getFilenameFromJson(versionJson);
+
+            Arena.pmsg(sender, Language.parse(MSG.UPDATER_DOWNLOADING, Language.parse(MSG.UPDATER_MODULES)));
+            downloadAndUnpackModules(getDownloadUrlFromJson(versionJson), filename);
+            String updateSuccess = getSuccessMessage(MSG.UPDATER_MODULES.toString(), onlineVersion);
+            LOG.info(updateSuccess);
+        } catch (IOException e) {
+            String errorMsg = Language.parse(MSG.UPDATER_DOWNLOAD_ERROR, Language.parse(MSG.UPDATER_MODULES));
+            Arena.pmsg(sender, errorMsg);
+            LOG.warning(errorMsg);
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Get current modules version based on version.lock
+     * @return version string (x.x.x format)
+     */
+    private String getModulesVersion() {
+        File lockFile = new File(this.getFilesFolder(), "version.lock");
+        if(lockFile.exists()) {
+            try {
+                List lines = Files.readAllLines(lockFile.toPath(), Charset.defaultCharset());
+                return lines.get(0);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Downloads new module package and unpack it
+     * @param downloadUrlStr Download url
+     * @param filename Packge file name
+     * @throws IOException
+     */
+    private static void downloadAndUnpackModules(String downloadUrlStr, String filename) throws IOException {
+        URL downloadUrl = new URL(downloadUrlStr);
+        File dataFolder = PVPArena.instance.getDataFolder();
+        File zipFile = new File(dataFolder, filename);
+        if (zipFile.exists()) {
+            zipFile.delete();
+        }
+        ReadableByteChannel readableByteChannel = Channels.newChannel(downloadUrl.openStream());
+        FileOutputStream outputStream = new FileOutputStream(zipFile);
+        outputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
+        outputStream.close();
+        deleteDirectory(getFilesFolder());
+        ZipUtil.unzip(zipFile, dataFolder);
+        zipFile.delete();
+    }
+
+    /**
+     * Returns PVP Arena "files" folder
+     * @return "files" folder
+     */
+    private static File getFilesFolder() {
+        return new File(PVPArena.instance.getDataFolder().getPath() + "/files");
+    }
+
+    /**
+     * Removes recusively a directory
+     * @param directoryToBeDeleted directory to be deleted
+     */
+    private static void deleteDirectory(File directoryToBeDeleted) {
+        File[] allContents = directoryToBeDeleted.listFiles();
+        if (allContents != null) {
+            for (File file : allContents) {
+                deleteDirectory(file);
+            }
+        }
+        directoryToBeDeleted.delete();
+    }
+}
diff --git a/src/net/slipcor/pvparena/updater/PluginUpdater.java b/src/net/slipcor/pvparena/updater/PluginUpdater.java
new file mode 100644
index 000000000..515998886
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/PluginUpdater.java
@@ -0,0 +1,115 @@
+package net.slipcor.pvparena.updater;
+
+import com.google.gson.JsonObject;
+import net.slipcor.pvparena.PVPArena;
+import net.slipcor.pvparena.core.Language;
+import org.bukkit.Bukkit;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.List;
+
+import static net.slipcor.pvparena.core.Language.MSG;
+
+/**
+ * Manage plugin versions and updates
+ */
+public class PluginUpdater extends AbstractUpdater {
+
+    private static final String API_URL = "https://api.github.com/repos/Eredrim/pvparena/releases/latest";
+    private static final String CONFIG_NODE = "update.plugin";
+    private File pluginJarFile;
+
+    /**
+     * Construct a plugin updater
+     * @param msgList Reference to UpdateChecker message list
+     */
+    public PluginUpdater(List msgList, File pluginJarFile) {
+        super(msgList, CONFIG_NODE);
+        this.pluginJarFile = pluginJarFile;
+    }
+
+    /**
+     * Run plugin updaters : checks version and downloads update according to config
+     * @throws IOException Exception if can't connect to github API
+     */
+    protected void runUpdater() throws IOException {
+        String currentVersion = PVPArena.instance.getDescription().getVersion().replace("v", "");
+        URL githubApi = new URL(API_URL);
+        URLConnection connection = githubApi.openConnection();
+        JsonObject versionJson = getVersionJson(connection.getInputStream());
+        String onlineVersion = getOnlineVersionFromJson(versionJson);
+
+        if(isUpToDate(currentVersion, onlineVersion)) {
+            LOG.info("PVP Arena is up to date");
+        } else {
+            String updateInfo = getAnnounceMessage(MSG.UPDATER_PLUGIN.toString(), onlineVersion, currentVersion);
+            LOG.info(updateInfo);
+            if(this.updateMode == UpdateMode.ANNOUNCE) {
+                this.updateMsgList.add(updateInfo);
+            } else if(this.updateMode == UpdateMode.DOWNLOAD ) {
+                String filename = getFilenameFromJson(versionJson);
+                LOG.info("Downloading update...");
+                try {
+                    downloadPlugin(getDownloadUrlFromJson(versionJson), filename);
+                    String updateSuccess = getSuccessMessage(MSG.UPDATER_PLUGIN.toString(), onlineVersion) + " " +
+                            Language.parse(MSG.UPDATER_RESTART);
+                    LOG.info(updateSuccess);
+                    this.updateMsgList.add(updateSuccess);
+                    this.planPluginRenaming(filename);
+                } catch (IOException e) {
+                    LOG.warning("Error during plugin update");
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * Downloads new plugin version and put it into "upadate" folder
+     * @param downloadUrlStr Download url
+     * @param filename Name of file to download
+     * @throws IOException Exception if download fails
+     */
+    private static void downloadPlugin(String downloadUrlStr, String filename) throws IOException {
+        URL downloadUrl = new URL(downloadUrlStr);
+        final File updateFolder = Bukkit.getServer().getUpdateFolderFile();
+        if (!updateFolder.exists()) {
+            updateFolder.mkdirs();
+        }
+        final File pluginFile = new File(updateFolder, filename);
+        if (pluginFile.exists()) {
+            pluginFile.delete();
+        }
+        ReadableByteChannel readableByteChannel = Channels.newChannel(downloadUrl.openStream());
+        FileOutputStream outputStream = new FileOutputStream(pluginFile);
+        outputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
+        outputStream.close();
+    }
+
+    /**
+     * Creates a runnable to rename current plugin jar with new jar name in order to spigot updater
+     * could replace the plugin by the "update" folder one.
+     * @param fileName name of downloaded file (currently in "update" folder)
+     */
+    private void planPluginRenaming(String fileName) {
+        final File pluginJarFile = this.pluginJarFile;
+        final String newFileName = fileName;
+        this.toRunOnDisable = new Runnable() {
+            @Override
+            public void run() {
+                String currentFileName  = pluginJarFile.getName();
+                File newJarFile = new File(pluginJarFile.getPath().replace(currentFileName, newFileName));
+                if(!newJarFile.exists()) {
+                    LOG.info("Renaming PVP Arena jar file. It will be replaced by the update on the next startup.");
+                    pluginJarFile.renameTo(newJarFile);
+                }
+            }
+        };
+    }
+}
diff --git a/src/net/slipcor/pvparena/updater/UpdateChecker.java b/src/net/slipcor/pvparena/updater/UpdateChecker.java
new file mode 100644
index 000000000..49c15120c
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/UpdateChecker.java
@@ -0,0 +1,54 @@
+package net.slipcor.pvparena.updater;
+
+import net.slipcor.pvparena.PVPArena;
+import net.slipcor.pvparena.core.Language;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Starts updaters and displays messages when player joins server
+ */
+public class UpdateChecker {
+    private List updateMsgList;
+    private PluginUpdater pluginUpdater;
+
+    /**
+     * Start plugin and modules updater
+     * @param pluginJarFile plugin jar file
+     */
+    public UpdateChecker(File pluginJarFile) {
+        this.updateMsgList = new ArrayList<>();
+
+        this.pluginUpdater = new PluginUpdater(this.updateMsgList, pluginJarFile);
+        ModulesUpdater modulesUpdater = new ModulesUpdater(this.updateMsgList);
+        new Thread(this.pluginUpdater).start();
+        new Thread(modulesUpdater).start();
+    }
+
+    /**
+     * Run methods for plugin updater during plugin disabling
+     */
+    public void runOnDisable() {
+        this.pluginUpdater.runOnDisable();
+    }
+
+    /**
+     * Send update message to players (OPs) on login
+     * @param player player who joins server
+     */
+    public void displayMessage(final Player player) {
+        Bukkit.getScheduler().scheduleSyncDelayedTask(PVPArena.instance, new Runnable() {
+            @Override
+            public void run() {
+                for(String message : updateMsgList) {
+                    player.sendMessage(Language.parse(Language.MSG.MESSAGES_GENERAL, "PVP Arena", message));
+                }
+            }
+        }, 20L);
+
+    }
+}
diff --git a/src/net/slipcor/pvparena/updater/UpdateMode.java b/src/net/slipcor/pvparena/updater/UpdateMode.java
new file mode 100644
index 000000000..d0c0adc86
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/UpdateMode.java
@@ -0,0 +1,19 @@
+package net.slipcor.pvparena.updater;
+
+public enum UpdateMode {
+    OFF, ANNOUNCE, DOWNLOAD;
+
+    public static UpdateMode getBySetting(final String setting) {
+        if (ANNOUNCE.name().equalsIgnoreCase(setting)) {
+            return ANNOUNCE;
+        }
+        if (DOWNLOAD.name().equalsIgnoreCase(setting)) {
+            return DOWNLOAD;
+        }
+        //Retro-compatibility
+        if ("both".equalsIgnoreCase(setting)) {
+            return DOWNLOAD;
+        }
+        return OFF;
+    }
+}
\ No newline at end of file
diff --git a/src/net/slipcor/pvparena/updater/ZipUtil.java b/src/net/slipcor/pvparena/updater/ZipUtil.java
new file mode 100644
index 000000000..037f0c7aa
--- /dev/null
+++ b/src/net/slipcor/pvparena/updater/ZipUtil.java
@@ -0,0 +1,61 @@
+package net.slipcor.pvparena.updater;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Util class to manage zip files
+ */
+public class ZipUtil {
+    /**
+     * Unzip a zip archive in destDir directory
+     * @param zipFile The file to unzip
+     * @param destDir Location where unzip the zip file
+     * @throws IOException Thrown an error is raised during unzipping
+     */
+    public static void unzip(File zipFile, File destDir) throws IOException {
+        byte[] buffer = new byte[1024];
+        ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
+        ZipEntry zipEntry = zis.getNextEntry();
+        while (zipEntry != null) {
+            File newFile = newFile(destDir, zipEntry);
+            if(zipEntry.getName().endsWith("/")) {
+                newFile.mkdirs();
+            } else {
+                FileOutputStream fos = new FileOutputStream(newFile);
+                int len;
+                while ((len = zis.read(buffer)) > 0) {
+                    fos.write(buffer, 0, len);
+                }
+                fos.close();
+            }
+            zipEntry = zis.getNextEntry();
+        }
+        zis.closeEntry();
+        zis.close();
+    }
+
+    /**
+     * Creates a new file based on a zip entry
+     * @param destinationDir extracting location of the entry
+     * @param zipEntry a zip entry
+     * @return new file created
+     * @throws IOException Thrown if the is an error during file creation
+     */
+    private static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
+        File destFile = new File(destinationDir, zipEntry.getName());
+
+        String destDirPath = destinationDir.getCanonicalPath();
+        String destFilePath = destFile.getCanonicalPath();
+
+        if (!destFilePath.startsWith(destDirPath + File.separator)) {
+            throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
+        }
+
+        return destFile;
+    }
+}
diff --git a/src/plugin.yml b/src/plugin.yml
index dc4d55060..a85f83219 100644
--- a/src/plugin.yml
+++ b/src/plugin.yml
@@ -1,10 +1,11 @@
 name: pvparena
 author: slipcor
-authors: [slipcor]
+authors: [slipcor, Eredrim]
 prefix: PVP Arena
 main: net.slipcor.pvparena.PVPArena
-version: 1.3.4.jenkins-build-number
-softdepend: [Spout,Multiverse-Core,MultiWorld,WormholeXTreme,Vault,WorldEdit,LibsDisguises,DisguiseCraft,TagAPI,My Worlds,CrackShot]
+version: ${project.version}${buildVersion}
+api-version: 1.13
+softdepend: [Spout,Multiverse-Core,MultiWorld,WormholeXTreme,Vault,WorldEdit,WorldGuard,LibsDisguises,DisguiseCraft,My Worlds,CrackShot]
 description: create, manage and enhance PvP arenas
 website: http://dev.bukkit.org/server-mods/pvparena
 dev-url: http://dev.bukkit.org/server-mods/pvparena