您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
weeb strikes again
当前为
// ==UserScript== // @name Sun:Raise - zombs.io // @namespace http://tampermonkey.net/ // @version 0.80 // @description weeb strikes again // @author rdm // @match *://zombs.io/ // @icon https://media.discordapp.net/attachments/854376044522242059/1067302959765016656/latest.png // @grant none // @license GNU GPLv3 // @noframes // ==/UserScript== /* @Credit * i have to give credit where credit is due, * most of the images used in this mod, including: * + intro background (#hud-intro::before), * + theme-character (.hud-intro-character) * is taken from Arcaea, this mod is themed to look * like Arcaea's UI. * * visit Arcaea at https://arcaea.lowiro.com/ and * check out the game on Google's Play Store and * Apple's App Store. */ // day 1 (0.1) : intro styles done // day 2 (0.2) : menu styles done // day 3 (0.3) : ahrc, rb, autoup done + polishing // day 4 (0.4) : entering unfamiliar territory with scanner // day 5 (0.41): polishing // day ? (0.42): beta release // v0.5 : added resizeable wall blocks // v0.6 : auto heal & ?????????????????? // v0.7 : unlimited slots base saver // v0.71 : shop shortcuts // v0.73 : shop shortcut fixes & added entity preserver // v0.80 : raid defending tools (in Misc.) and Grouping Grid (courtesy of ABCxFF) added const fontAwesome = document.createElement("script"); fontAwesome.type = "text/javascript"; fontAwesome.src = "https://kit.fontawesome.com/1c239b2e80.js"; document.head.appendChild(fontAwesome); document.querySelectorAll('.ad-unit, #hud-intro > div.hud-intro-wrapper > h1, #hud-intro > div.hud-intro-footer > a:nth-child(2), #hud-intro > div.hud-intro-footer > a:nth-child(4), #hud-menu-shop > div.hud-shop-grid > a:nth-child(10), #hud-intro > div.hud-intro-wrapper > h2, .hud-intro-left, .hud-intro-guide, .hud-intro > .hud-intro-stone, .hud-intro >.hud-intro-tree, .hud-intro-youtuber, .hud-intro-more-games, .hud-intro-social, .hud-respawn-corner-bottom-left, .hud-respawn-twitter-btn, .hud-respawn-facebook-btn').forEach(el => el.remove()); const css = ` /* @Root */ :root { --menu-background: hsl(29deg 69% 34% / 40%); --normal-btn: hsl(44deg 58% 60%); --light-hover-btn: hsl(44deg 88% 70%); } ::-webkit-scrollbar { width: 12px; height: 0px; border-radius: 10px; background-color: rgba(0, 0, 0, 0); } ::-webkit-scrollbar-thumb { border-radius: 10px; background-image: url(https://cdn.discordapp.com/attachments/854376044522242059/924927754326142976/whiteslider.png); } /* @Keyframes */ @keyframes parallax-bg { 0%, 100% { background-position: top left; } 50% { background-position: bottom right; } } @keyframes bounce { 50% { background-position-y: -10px; } 100% { background-position-y: 0px; } } @keyframes slide-in-left { 0% { left: -100%; } 100% { left: 0px; } } @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } /* @ButtonStyles */ .no-bg { display: inline-block; height: 40px; line-height: 40px; padding: 0 20px; color: #eee; background: none; box-shadow: none; border: none; cursor: pointer; } .underline-white { border-bottom: 3px solid #eee; } .underline-red { border-bottom: 3px solid red; } .hud-settings-options .underline-red { border-bottom: 3px solid red; } .btn-important { display: inline-block; height: 40px; line-height: 40px; padding: 0 20px; color: var(--normal-btn); background: none; border: none; cursor: pointer; transition: all 0.15s ease-in-out; border-bottom: 3px solid var(--normal-btn); box-shadow: inset 0 -7px 9px -7px var(--normal-btn); } .btn-important:hover { filter: saturate(200%); } /* @IntroStyles */ .hud-intro::before { background-image: url('https://media.discordapp.net/attachments/854376044522242059/1067303856893071481/1000.png'); background-size: 200%; background-position: top; filter: blur(10px); animation-name: parallax-bg; animation-duration: 400s; animation-timing-function: linear; animation-iteration-count: infinite; } .hud-intro::after { background: rgba(0, 0, 0, 0.2); } #hud-intro > div.hud-intro-corner-top-left { top: 0px; left: 0px; /* display: none; */ } .hud-intro-stick { display: block; position: relative; width: 30vw; background: #eee; height: 30px; box-shadow: 0px 5px 10px 2px rgb(0 0 0 / 70%); font-weight: 700; padding: 4px; } .hud-intro-stick::before { display: block; position: absolute; content: ""; right: -12px; top: 3px; height: 22.5px; width: 22.5px; transform: rotate(45deg); background: #eee; } .hud-intro-stick::after { display: block; position: absolute; content: ""; right: -11px; top: 4px; height: 18px; width: 18px; transform: rotate(45deg); background: black; border: 2px double #eee; } .hud-intro-scan-data { width: 30vw; min-width: 100%; height: fit-content; background: rgba(0, 0, 0, 0.4); border-bottom-right-radius: 4px; padding: 10px; zoom: 90%; color: #eee; max-height: 400px; overflow: scroll; } .hud-intro-scan-data .hud-intro-scan-data-player { position: relative; display: block; margin: 0 0 8px; padding: 0 90px 0 40px; height: 20px; line-height: 20px; font-size: 13px; font-family: 'Open Sans', sans-serif; } .hud-intro-scan-data .hud-intro-scan-data-player:last-child { margin-bottom: 0; } .hud-intro-scan-data .hud-intro-scan-data-player.is-header * { color: rgba(255, 255, 255, 0.6) !important; } .hud-intro-scan-data .hud-intro-scan-data-player .player-rank { position: absolute; top: 0; bottom: 0; left: 0; color: rgba(255, 255, 255, 0.6); } .hud-intro-scan-data .hud-intro-scan-data-player .player-name { display: block; height: 20px; line-height: 20px; } .hud-intro-scan-data .hud-intro-scan-data-player .player-score { position: absolute; top: 0; bottom: 0; right: 50px; color: rgba(255, 255, 255, 1); } .hud-intro-scan-data .hud-intro-scan-data-player .player-wave { position: absolute; top: 0; bottom: 0; right: 0; color: rgba(255, 255, 255, 0.7); } .hud-intro-scan-data hr { border: 1px dashed #eee; margin: 20px 0; } #hud-intro > div.hud-intro-corner-top-right { background: rgba(0, 0, 0, 0.3); padding: 15px; top: 0px; right: 0px; border-bottom-left-radius: 4px; } #hud-intro > div.hud-intro-corner-top-right::before { display: block; position: absolute; content: ""; width: 100%; height: 2px; background: linear-gradient(to right, transparent 5%, rgba(255, 255, 255, 0.9)); right: 10px; bottom: 0px; } #hud-intro > div.hud-intro-corner-top-right::after { display: block; position: absolute; content: ""; width: 15px; height: 15px; transform: rotate(45deg); margin: 10px; border: 4px solid white; background: black; right: 0px; bottom: -20px; box-shadow: none; border-style: double; } .hud-intro .hud-intro-footer { left: 20px; right: unset; text-shadow: 0 1px 3px rgb(0 0 0 / 50%); z-index: 20 !important; } #hud-intro > div.hud-intro-wrapper > div { z-index: 31; margin: 50px 30vw 0 0; } #hud-intro > div.hud-intro-wrapper > div > div { display: flex; flex-direction: row; flex-wrap: wrap; width: 380px; padding-bottom: 0px; padding-top: 37.5px; } .hud-intro-server-container { display: flex; flex-direction: row; justify-content: space-around; margin-bottom: 10px; } .hud-intro-server-decorator { width: 0px; content: ""; height: 0px; border-bottom: 50px solid #eee; border-right: 50px solid transparent; position: relative; bottom: 0px; } #hud-intro > div.hud-intro-wrapper > div > div > div > div > select { border-bottom-right-radius: 0px; border-top-right-radius: 0px; } .hud-intro-name-container { display: flex; flex-direction: row; justify-content: space-around; margin-bottom: 5px; } .hud-intro-name-decorator { width: 0px; content: ""; height: 0px; border-top: 50px solid #eee; border-right: 50px solid transparent; position: relative; bottom: 0px; } .hud-intro-name-decorator::after { content: ""; position: absolute; bottom: 54px; left: -200px; width: 120px; border-bottom: 3px dashed #eee; } #hud-intro > div.hud-intro-wrapper > div > div > div > div > input { border-bottom-right-radius: 0px; border-top-right-radius: 0px; padding: 8px 30px 8px 14px; } #saved-names { position: absolute; top: -34px; left: -20px; box-shadow: none; border: none; background: none; width: 20px; } #scan-btn { cursor: pointer; width: 120px; position: relative; right: -160px; top: -20px; height: 120px; margin: -60px; filter: drop-shadow(7.5px 2.5px 0px rgba(0, 0, 0, 0.5)); } .hud-intro .hud-intro-form .hud-intro-play { width: 150px; height: 150px; transform: rotate(45deg); border: 5px solid white; margin-bottom: -20px; margin-left: -7.5px; margin-right: -150px; margin-top: -17.5px; background-image: url(https://cdn.discordapp.com/attachments/854376044522242059/976742118661980160/Story_crimsonsolace.webp); background-size: 150%; padding: 0 0 0 0; background-position-y: center; background-position-x: center; transition: all 0.15s ease-in-out; z-index: 21 !important; position: relative; filter: drop-shadow(10px -5px 0px rgba(0, 0, 0, 0.4)); } .hud-intro .hud-intro-form .hud-intro-play:hover { filter: drop-shadow(10px -5px 0px rgba(0, 0, 0, 0.4)) saturate(200%); box-shadow: inset 0 0 20px 3px rgb(0 0 0 / 45%); } #playspan { position: relative; font-weight: 900; z-index: 22; font-size: xx-large; text-shadow: 1px 1px 3px black; cursor: pointer; font-family: 'Open Sans'; pointer-events: none; top: -75px; left: 65px; margin: -20px -30px; } .hud-intro .hud-intro-form .hud-intro-play::after { display: block; content: ""; position: absolute; top: -15px; left: -15px; width: 40px; height: 40px; border-top: 5px solid white; border-left: 5px solid white; border-top-left-radius: 5px; pointer-events: none; } #hud-intro > div.hud-intro-wrapper > div > div > label { margin: -30px 0 0 0; } .hud-intro .hud-intro-decoration { display: flex; position: absolute; bottom: 0px; width: 100%; pointer-events: none; } .hud-intro .hud-intro-decoration > * { pointer-events: none; } .hud-intro-decoration .hud-intro-left-triangle { height: 300px; width: 600px; } .hud-intro-decoration .hud-intro-left-triangle::before { width: 100%; height: 100%; transform: rotate(30deg); content: ''; display: block; position: absolute; left: -40%; bottom: -50%; background-image: linear-gradient( 45deg, rgba(60, 50, 93, 0.8) 25%, rgba(60, 50, 93, 0.7) 25%, rgba(60, 50, 93, 0.7) 50%, rgba(60, 50, 93, 0.8) 50%, rgba(60, 50, 93, 0.8) 75%, rgba(60, 50, 93, 0.7) 75%, rgba(60, 50, 93, 0.7) ); background-size: 10px 10px; } .hud-intro-decoration .hud-intro-right-triangle { height: 700px; width: 700px; } .hud-intro-decoration .hud-intro-right-triangle::before { width: 100%; height: 100%; transform: rotate(-45deg); content: ''; display: block; position: absolute; right: -50%; bottom: -50%; color: white; background-image: linear-gradient(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.9)), url(https://cdn.discordapp.com/attachments/854376044522242059/925743376505118720/light2.webp); background-position-x: 130px; filter: drop-shadow(4px 2px 6px black); } .hud-intro-decoration .hud-intro-character { display: block; position: absolute; height: 70vh; width: 70vh; bottom: 7.5vh; right: calc(20vw - 35vh); cursor: default; z-index: 30; filter: drop-shadow(15px 15px 0px rgba(0, 0, 0, 0.3)); background-size: cover; background-image: url(https://media.discordapp.net/attachments/854376044522242059/1067321580906086450/1000.png); background-repeat: no-repeat; animation-name: bounce; animation-duration: 10s; animation-iteration-count: infinite; } .hud-intro-credits { position: fixed; display: block; bottom: 40px; left: 20px; color: rgba(255, 255, 255, 0.4); } /* @UIBuildingOverlay */ .hud-building-overlay { background: var(--menu-background); border: 3px solid white; padding: 12px; width: 370px; } .hud-building-overlay::after { border-top: 6px solid white; top: 101%; } .hud-building-overlay .hud-tooltip-health .hud-tooltip-health-bar { background: #bf6509; } /* @UIChatStyles */ .hud-chat { resize: vertical; max-height: 380px; min-height: 75px; overflow-y: auto; border-radius: 4px 4px 4px 0; } .hud-chat .hud-chat-message { display: block; position: relative; width: 90%; white-space: unset; word-break: break-all; overflow: visible; } .hud-chat .hud-chat-message strong { display: inline-block; } .hud-chat .hud-chat-message > small { position: absolute; right: -12%; font-weight: bold; opacity: 0.4; } /* @UIZoomStyles */ .interaction-wheel { display: none; height: 250px; width: 250px; border: 80px solid rgba(0, 0, 0, 0.4); border-radius: 125px; position: fixed; top: calc(50vh - 125px); left: calc(50vw - 125px); } .tag-is-disabled { opacity: 0.4; pointer-events: none; cursor: no-drop; } #next-wheel { background: rgba(0, 0, 0, 0.4); color: white; right: -120px; position: absolute; top: -80px; height: 60px; width: 60px; border-radius: 50%; border: none; cursor: pointer; } #next-wheel::after { content: ' '; position: absolute; width: 100%; height: 100%; background-image: url(https://cdn.discordapp.com/attachments/854376044522242059/947717701839757392/Friends_Mutual.webp); background-size: 90%; top: 5%; left: 5%; } #zoom-mode { background: rgba(0, 0, 0, 0.4); color: white; left: -120px; position: absolute; bottom: -80px; height: 60px; width: 60px; border-radius: 50%; border: none; text-align: center; padding: 20px 0; font-family: 'Hammersmith One'; } #zoom-controls { background: rgba(0, 0, 0, 0.2); color: white; right: calc(50% - 65px); position: fixed; top: 10px; height: 60px; width: 130px; border-radius: 4px; border: none; text-align: start; padding: 10px; font-family: 'Hammersmith One'; } .hud-zoom-item { width: 48px; height: 48px; color: white; position: absolute; transition: all 0.15s ease-in-out; } .zoom-reset { top: -60px; left: calc(50% - 15px); } .zoom-up { left: -60px; top: calc(50% - 15px); } .zoom-down { top: calc(50% - 15px); right: -80px; } .zoom-prop { font-size: 20px; bottom: -80px; left: 25%; } /* @UIQuickBuy */ .hud-center-toolbar { width: 30vw; height: 68px; z-index: 9999; background: rgba(0, 0, 0, 0.4); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; top: -20px; position: relative; overflow-x: auto; padding: 10px; display: flex; flex-wrap: nowrap; max-width: max-content; } .hud-center-toolbar .is-disabled { pointer-events: none; opacity: 0.4 !important; } .hud-center-toolbar .hud-center-toolbar-item { position: relative; flex: 0 0 auto; display: inline-block; width: 48px; height: 48px; line-height: 48px; margin: 0 4px; text-align: center; text-decoration: none; background: rgba(255, 255, 255, 0.1); color: rgba(0, 0, 0, 0.8); border-radius: 4px; transition: all 0.15s ease-in-out; } .hud-center-toolbar .hud-center-toolbar-item::after { content: ' '; display: block; width: 32px; height: 32px; margin: 8px auto; background-size: contain; background-position: center; background-repeat: no-repeat; opacity: 0.7; transition: all 0.15s ease-in-out; } /* @UIMisc. */ #joinWithPsk { display: none; background-color: rgba(0, 0, 0, 0.4); padding: 4px 5px; border-radius: 8px; color: rgb(255, 255, 255); width: 30vw; height: 40px; position: fixed; left: 35vw; top: 60vh; } div > div > a.btn.btn-green.hud-confirmation-accept { background: var(--normal-btn); } /* @UIMenuShopStyles */ #hud-menu-shop { top: calc(50vh - 250px); left: calc(50vw - 345px); width: 690px; height: 500px; background: var(--menu-background); border: 4px solid white; margin: 0 0 0 0; padding: 20px 20px 20px 20px; z-index: 20; } .hud-menu-shop .hud-shop-grid { height: 360px; } .hud-shop-grid::after { font-size: 200px; position: absolute; top: -30px; right: -70px; width: 40%; height: 40%; z-index: -69; font-family: "Font Awesome 5 Free"; font-weight: 10; content: "\\f185"; opacity: 0.1; color: white; } .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip { background: var(--normal-btn); } .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip:hover, .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip:active { background: var(--light-hover-btn); } .hud-menu-shop .hud-shop-grid .hud-shop-item .hud-shop-item-actions .hud-shop-actions-equip.is-disabled { background: none; } .hud-menu-shop .hud-shop-grid .hud-shop-item[data-item=HatComingSoon] .hud-shop-item-coming-soon { background: none; } /* @UIMenuPartyStyles */ #hud-menu-party { top: calc(50vh - 240px); left: calc(50vw - 305px); margin: 0; width: 610px; height: 480px; background-color: var(--menu-background); border: 4px solid white; z-index: 20; } .hud-party-members::after { font-size: 200px; position: absolute; bottom: 30px; left: -10px; width: 40%; height: 40%; z-index: -69; font-family: "Font Awesome 5 Free"; font-weight: 10; content: "\\f185"; opacity: 0.1; color: white; } .hud-menu-party .hud-party-members .hud-member-link::before { display: block; position: absolute; content: " "; left: 0px; bottom: 0px; height: 3px; width: 30%; } #hud-menu-party > div.hud-party-members > div:nth-child(1)::before { background: #8473d4; } #hud-menu-party > div.hud-party-members > div:nth-child(2)::before { background: #d6ab35; } #hud-menu-party > div.hud-party-members > div:nth-child(3)::before { background: #76bd2f; } #hud-menu-party > div.hud-party-members > div:nth-child(4)::before { background: #d67820; } .hud-party-grid::after { font-size: 200px; position: absolute; bottom: 30px; left: -10px; width: 40%; height: 40%; z-index: -69; font-family: "Font Awesome 5 Free"; font-weight: 10; content: "\\f185"; opacity: 0.1; color: white; } .hud-menu-party .hud-party-grid .hud-party-link.is-active { background: var(--normal-btn) !important; } .hud-menu-party .hud-party-visibility { width: 275.5px; margin: 10px 3px 0 0; background: var(--normal-btn); } .hud-menu-party .hud-party-share { width: 395px; margin: 0 0 0 5px; } /* @UIMenuSettingsStyles */ #hud-menu-settings { background-color: var(--menu-background); border: 4px solid white; margin: 0px; top: calc(50vh - 275px); left: calc(50vw - 360px); width: 720px; height: 550px; overflow: hidden; } .hud-menu-settings::before { font-size: 200px; position: absolute; top: -90px; left: calc(50% - 100px); width: 40%; height: 40%; z-index: -69; font-family: "Font Awesome 5 Free"; font-weight: 10; content: "\\f185"; opacity: 0.1; color: white; } #hud-menu-settings::after { display: block; position: absolute; content: ""; width: 25px; height: 25px; transform: rotate(45deg); margin: 10px; background: white; right: -25px; top: 73px; box-shadow: none; } .hud-menu-settings .hud-settings-grid { height: 390px; margin: 90px 0 0; overflow: hidden; padding: unset; } .hud-settings-page { width: 100%; height: 100%; } .hud-settings-page > span { position: relative; margin: auto; font-size: 17px; opacity: 0.7; } .hud-settings-page .coming-soon { } .hud-settings-options { display: inline-block; position: relative; width: 50%; height: 100%; background: rgba(0, 0, 0, 0.2); padding: 15px; overflow: auto; } .hud-settings-options > div { opacity: 0.8; display: block; position: relative; height: 100px; border-bottom: 2px dashed white; margin-bottom: 15px; } .hud-settings-options h2 { font-family: "Open Sans"; margin: 5px 0 10px 0; font-size: 1.4em; } .hud-settings-options span { display: block; position: absolute; opacity: 0.7; width: 60%; -webkit-font-smoothing: antialiased; } .hud-settings-options button { position: absolute; top: calc(50% - 20px); right: 35px; height: 40px; width: 25%; background: unset; border: none; border-bottom: 3px solid white; color: white; font-size: 18px; cursor: pointer; transition: all 0.15s ease-in-out; } .hud-settings-options a { position: absolute; top: calc(50% - 10px); right: -5px; height: 20px; width: 20px; background: unset; opacity: 0.4; transition: all 0.15s ease-in-out; } .hud-settings-options a::before { font-family: "Font Awesome 5 Free"; content: "\\f054"; font-size: 20px; height: 100%; width: 100%; display: block; font-weight: 900; } .hud-settings-options a:hover { opacity: 1; } .hud-settings-more { position: relative; display: inline-block; width: 50%; height: 100%; padding: 15px; overflow: auto; } .hud-settings-more input { height: 40px; width: 100%; background: rgba(0, 0, 0, 0.2); border: 2px dashed rgba(255, 255, 255, 0.7); border-radius: 4px; padding: 5px; color: #eee; margin: 10px 0; } .hud-settings-more span { display: block; opacity: 0.5; } .hint-controls { position: absolute; display: flex; flex-direction: column; zoom: 83%; width: fit-content; height: 84px; top: 55px; left: 30px; overflow: scroll; } .hint-controls > li { opacity: 0.5; -webkit-font-smoothing: antialiased; margin: 0 5px 0 0; } #select-page { display: flex; justify-content: space-evenly; position: absolute; top: 75px; right: 0px; background-image: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent); box-shadow: 10px 0 rgb(0 0 0 / 40%); width: 200px; border: 2px solid; border-image: linear-gradient(to right, transparent 5%, rgb(163 163 43) 35%, rgb(206 120 55) 95%); border-image-slice: 1; border-left: none; border-right: none; border-top: none; padding-left: 20px; } #page-name { display: inline-block; -webkit-font-smoothing: antialiased; position: relative; transform: translate(0px, 9px); } /* @UIMenuMoreCustomStyles */ .base-card { position: relative; display: block; width: 100%; height: 64px; margin: 0 0 10px; padding: 10px 10px 10px 10px; text-decoration: none; background: rgba(255, 255, 255, 0.1); cursor: pointer; color: #eee; border-radius: 3px; transition: all 0.15s ease-in-out; text-align: left; } .base-card:hover { background: rgba(255, 255, 255, 0.2); } #base-management { position: absolute; top: 0px; width: 95%; height: 75%; margin: 0px; padding-right: 10px; overflow: scroll; } #base-management > h2 { display: inline-block; margin: 10px 0 10px; font-weight: 600; -webkit-font-smoothing: antialiased; } #base-management > hr { width: 87%; opacity: 0.4; } #save-config { position: absolute; top: 285px; right: 15px; } `; const styles = document.createElement("style"); styles.type = "text/css"; styles.appendChild(document.createTextNode(css)); document.head.appendChild(styles); function getClass(DOMClass) { return document.getElementsByClassName(DOMClass); }; function getId(DOMId) { return document.getElementById(DOMId); }; /* @Intro */ getId("hud-intro").insertAdjacentHTML("beforeend", ` <div class="hud-intro-decoration" id="hud-intro-decoration"> <a class="hud-intro-left-triangle"></a> <a class="hud-intro-right-triangle"></a> <a class="hud-intro-character"></a> </div> <div class="hud-intro-credits"> <span>Sun<strong>:Raise</strong></span> <i class="fas fa-sun"></i> </div> `); getClass("hud-intro-corner-top-left")[0].insertAdjacentHTML("afterbegin", ` <a class="hud-intro-stick">Scanner</a> <div class="hud-intro-scan-data"> <span style="display: block;position: relative;opacity: 0.7;text-wrap: wrap;">Scanned data will be shown here once done.</span> </div> `); getClass("hud-intro-form")[0].insertAdjacentHTML("afterbegin", ` <div style="margin: 0 10px 0 0;"> <div class="hud-intro-name-container"> <a class="hud-intro-name-decorator"><select id="saved-names"></select></a> </div> <div class="hud-intro-server-container"> <a class="hud-intro-server-decorator"></a> </div> </div> <div></div> <img id="scan-btn" src="https://cdn.discordapp.com/attachments/854376044522242059/926035565554589696/scan.webp" onclick="window.sscs();" /> `); getClass("hud-intro-name-container")[0].insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > input")); getClass("hud-intro-server-container")[0].insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > select")); getClass("hud-intro-play")[0].innerText = ""; document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(2)").insertAdjacentElement("afterbegin", document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > button")); document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(2)").insertAdjacentHTML("beforeend", ` <span id="playspan">Play</span> `); const oldSubmit = game.ui.components.Intro.submitElem; const newSubmit = oldSubmit.cloneNode(true); oldSubmit.parentNode.replaceChild(newSubmit, oldSubmit); game.ui.components.Intro.submitElem = newSubmit; game.ui.components.Intro.onSubmitClick = function (_0x56b3b8) { const realNicknameLength = new Blob([this.nameInputElem.value]).size; if (realNicknameLength > 29) return void game.ui.components.Intro.onConnectionError('Your nickname length is too long. Please shorten it/use less special characters.'); const server = this.ui.getOption(`servers`)[this.serverElem.value]; localStorage.setItem(`name`, this.nameInputElem.value.trim()); this.connecting || ( this.connecting = true, getId("playspan").style && (getId("playspan").innerText = " "), this.connectionTimer = setTimeout(function() { this.onConnectionError(); }.bind(this), 15000), this.submitElem.innerHTML = '<span\x20class=\x22hud-loading\x22></span>', this.errorElem.style.display = `none`, this.ui.setOption(`nickname`,this.nameInputElem.value.trim()), this.ui.setOption(`serverId`, this.serverElem.value), game.network.connect(server) ); } newSubmit.onclick = game.ui.components.Intro.onSubmitClick.bind(game.ui.components.Intro); game.ui.components.Intro.onConnectionError = function (errorText) { errorText ||= `We were unable to connect to the gameserver. Please try another server.`; this.connecting = false; this.connectionTimer && ( clearInterval(this.connectionTimer), delete this.connectionTimer ); getId("playspan").style && (getId("playspan").innerText = "Play"); this.serverElem.classList.add('has-error'); this.errorElem.style.display = 'block'; this.errorElem.innerText = errorText; } game.ui.components.Intro.checkForPartyInvitation = function () { if (document.location.hash && !(document.location.hash.length < 2)) { var subString = document.location.hash.substring(2).split('/'), serverId = subString[0], partyShareKey = subString[1]; if (serverId && partyShareKey) { this.serverElem.setAttribute(`disabled`, `true`); document.querySelector("#hud-intro > div.hud-intro-wrapper > div > div > div:nth-child(1) > div.hud-intro-server-container > a").style.opacity = '0.4'; this.serverElem.querySelector('option[value=\x22' + serverId + '\x22]').setAttribute(`selected`, 'true'); this.partyShareKey = partyShareKey; /* Game.currentGame.network.addEnterWorldHandler(function (e) { if (e.allowed && !this.reconnectKey) { var packet = { 'name': `JoinPartyByShareKey`, 'partyShareKey': this.partyShareKey }; Game.currentGame.network.sendRpc(packet); } }); */ }; } }; game.ui.components.Intro.checkForPartyInvitation(); (function() { if (!localStorage.savedNames) return; let id = 0; const selectElem = getId("saved-names"), names = [], items = JSON.parse(localStorage.savedNames).map(nameUnfiltered => { const name = window.filterXSS(nameUnfiltered); names.push(nameUnfiltered); return `<option>${name}</option>`; }).join('\n'); selectElem.innerHTML = items; })(); getId("saved-names").addEventListener('change', (e) => { getClass("hud-intro-name")[0].value = e.target.selectedOptions[0].innerText; }); game.network.addEnterWorldHandler((e) => { if (!e.allowed) { try { getId("playspan").innerText = "Play"; game.ui.components.Intro.submitElem.innerText = ''; } catch {}; }; console.log(e); !localStorage.savedNames && (localStorage.savedNames = JSON.stringify([])); const willBeSaved = e.effectiveDisplayName, storage = JSON.parse(localStorage.savedNames); if (storage.find(i => i == willBeSaved) === undefined) { storage.push(willBeSaved); localStorage.savedNames = JSON.stringify(storage); } }); document.getElementsByClassName('hud-party-tag')[0].setAttribute('maxlength', 49); document.getElementsByClassName('hud-intro-name')[0].setAttribute('maxlength', 29); window.sscs = (selected = getClass("hud-intro-server")[0].value) => { const server = game.options.servers[selected]; const hostname = server.hostname; const url = `wss://${hostname}:443/`; let hasSentData = false; document.querySelector("#hud-intro > div.hud-intro-corner-top-left > div").innerHTML = ` <strong class="hud-loading" style="display: block;margin: auto;"></strong> <span style="display: block;margin: 10px 0 5px;position: relative;text-align: center;opacity: 0.7;">This may take 10-20 seconds.</span> `; const iframe = document.createElement('iframe'); iframe.src = `https://zombs.io/`; iframe.style.display = 'none'; document.body.append(iframe); game.network.connectionOptions = { ipAddress: server.ipAddress }; game.network.connected = true; iframe.addEventListener("load", () => { const _game = iframe.contentWindow.game; _game.network.connectionOptions = { ipAddress: server.ipAddress }; _game.network.connected = true; const ws = new WebSocket(url); ws.binaryType = "arraybuffer"; ws.isclosed = false; const loadLbPacket = () => { for (let i = 0; i < 30; i++) ws.send(new Uint8Array([3, 17, 123, 34, 117, 112, 34, 58, 49, 44, 34, 100, 111, 119, 110, 34, 58, 48, 125])); // move packet ws.send(new Uint8Array([7, 0])); // ping ws.send( new Uint8Array( [9,6,0,0,0,126,8,0,0,108,27,0,0,146,23,0,0,82,23,0,0,8,91,11,0,8,91,11,0,0,0,0,0,32,78,0,0,76,79,0,0,172,38,0,0,120,155,0,0, 166,39,0,0,140,35,0,0,36,44,0,0,213,37,0,0,100,0,0,0,120,55,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134,6,0,0] ) ); // metrics }; ws.onopen = (data) => { ws.network = new game.networkType(); ws.send(new Uint8Array([7, 0])); ws.sendPacket = (e, t) => { let enc; if (e == 6) { enc = _game.network.codec.encode(e, t); } else { enc = ws.network.codec.encode(e, t); } !ws.isclosed && ws.send(enc); }; ws.onRpc = (data) => { if(data.name === "SetPartyList") { ws.parties = data.response; }; if(data.name === "Leaderboard") { if (ws.b4) { window.appSsrs({ population: ws.pop, leaderboard: data, parties: ws.parties, server: server }); hasSentData = true; ws.close(); return; }; loadLbPacket(); ws.b4 = true; }; }; ws.onmessage = msg => { const dataArray = new Uint8Array(msg.data); let data; if (dataArray[0] == 5) { ws.network.codec.decodePreEnterWorldResponse = buffer => buffer; const _data = ws.network.codec.decode(msg.data); data = _game.network.codec.decodePreEnterWorldResponse(_data); data = {opcode: 5, ...data}; } else data = ws.network.codec.decode(msg.data); switch(data.opcode) { case 5: ws.sendPacket(4, { displayName: `${new Date().toLocaleString()}`, extra: data.extra }); break; case 4: if (!data.allowed) { const lbData = {name: "Leaderboard", response: [{name: "Server full.", uid: 727, rank: 0, score: 0, wave: 0}], opcode: 9}; window.appSsrs({ population: 32, leaderboard: lbData, parties: [], server: server }); hasSentData = true; } else { ws.sendPacket(6, {}); ws.sendPacket(3, { left: 1, up: 1 }); ws.sendPacket(3, {mouseMovedWhileDown: 0}); ws.sendPacket(3, {space: 0}); ws.sendPacket(3, {space: 1}); ws.pop = data.players; } break; case 9: ws.onRpc(data); break; }; }; ws.onclose = () => { ws.isclosed = true; if (!hasSentData) { const lbData = {name: "Leaderboard", response: [{name: "Unable to access.", uid: 727, rank: 0, score: 0, wave: 0}], opcode: 9}; window.appSsrs({ population: null, leaderboard: lbData, parties: [], server: server }); hasSentData = true; } iframe.remove(); } }; }); }; window.appSsrs = res => { console.log(res); if (res.population !== null) { getClass("hud-intro-server")[0].value = res.server.id; getClass("hud-intro-server")[0].selectedOptions[0].innerText = `${res.server.name} [${res.population}/32]`; } const leaderboard = res.leaderboard.response; const ssrs = getClass("hud-intro-scan-data")[0]; ssrs.innerHTML = ` <p>Population: ${res.population === null ? "Cannot fetch" : res.population}</p> <div> ${leaderboard.map(lb => { return ` <div class="hud-intro-scan-data-player"> <span class="player-rank">#${lb.rank + 1}</span> <strong class="player-name">${window.filterXSS(lb.name)}</strong> <span class="player-score">${lb.score.toLocaleString("en")}</span> <span class="player-wave">${lb.wave.toLocaleString("en")}</span> </div> `; }).join("\n")} </div> <hr /> <div> ${res.parties.map(p => { return ` <div class="hud-intro-scan-data-player"> <span class="player-rank">${p.memberCount}</span> <strong class="player-name">${window.filterXSS(p.partyName)}</strong> <span class="player-score">${p.isOpen ? "Public" : "Private"}</span> <span class="player-wave">${p.partyId}</span> </div> `; }).join("\n")} </div> `; }; /* @UI */ // @Chat game.ui.components.Chat.chatResize = function() { this.messagesElem.style.height = (this.componentElem.offsetHeight - 40) + "px"; this.componentElem.scrollTop = this.messagesElem.scrollHeight; } game.ui.components.Chat.blockedNames = []; game.ui.components.Chat.emojiList = { // static emojis hmm: "https://cdn.discordapp.com/emojis/724365641963929611.png?size=48", pog: "https://cdn.discordapp.com/emojis/721070353337811026.png?size=48", pepehands: "https://cdn.discordapp.com/emojis/733406770139103293.png?size=48", pepeEyes: "https://cdn.discordapp.com/emojis/869573233794486323.gif?size=48", pepeHappy: "https://cdn.discordapp.com/emojis/801475958883614811.png?size=48", sadge: "https://cdn.discordapp.com/emojis/826530556974989344.png?size=48", ha: "https://cdn.discordapp.com/emojis/782756472886525953.png?size=48", kekw: "https://cdn.discordapp.com/emojis/748511358076846183.png?size=48", pogEyes: "https://cdn.discordapp.com/emojis/786979080406564885.png?size=48", appalled: "https://cdn.discordapp.com/emojis/830880294881853530.png?size=48", pogYou: "https://cdn.discordapp.com/emojis/790293794716516430.png?size=48", pogChag: "https://cdn.discordapp.com/emojis/831156303497134090.png?size=48", pogey: "https://cdn.discordapp.com/emojis/790293759861719050.png?size=48", weirdChamp: "https://cdn.discordapp.com/emojis/757553915389673502.png?size=48", monkaS: "https://cdn.discordapp.com/emojis/757179783573405766.png?size=48", yep: "https://cdn.discordapp.com/emojis/758356179477987339.png?size=48", // animated emojis / gif weirdButOkay: "https://cdn.discordapp.com/emojis/831156194247966782.gif?size=48", pogpogpogpog: "https://cdn.discordapp.com/emojis/869580566096379974.gif?size=48", wooyeah: "https://cdn.discordapp.com/emojis/791008461420888084.gif?size=48", idk: "https://cdn.discordapp.com/emojis/882513306164805642.gif?size=48", }; game.ui.components.Chat.blockPlayer = function(name) { game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to block ${window.filterXSS(name)}?`, 3500, () => { this.blockedNames.push(name); for (let msg of Array.from(document.getElementsByClassName("hud-chat-message"))) { if (msg.childNodes[1].innerText === ' ' + name) { let bl = msg.childNodes[0]; bl.innerHTML = "Unblock"; bl.style.color = "blue"; bl.onclick = () => this.unblockPlayer(name); }; }; }, () => {}); }; game.ui.components.Chat.unblockPlayer = function(name) { this.blockedNames.splice(this.blockedNames.indexOf(name), 1); for (let msg of Array.from(document.getElementsByClassName("hud-chat-message"))) { if (msg.childNodes[1].innerText === ' ' + name) { let bl = msg.childNodes[0]; bl.innerHTML = "Block"; bl.style.color = "red"; bl.onclick = () => this.blockPlayer(name); }; }; }; game.ui.components.Chat.onMessageReceived = function(e) { if (this.blockedNames.includes(e.displayName) || window.chatDisabled) return; let a = this, b = window.filterXSS(e.displayName), c = window.filterXSS(e.message) .replace(/(?:f|F)uck/gi, `<img src="https://cdn.discordapp.com/emojis/907625398832070667.png?size=80" height="16" width="18" style="margin: 1px 0 0 0;"></img>`) .replace(/s[3e]x+/gi, `<img src="https://cdn.discordapp.com/emojis/953759638350872666.gif?size=80&quality=lossless" height="16" width="18" style="margin: 1px 0 0 0;"></img>`) .replace(/n+[i1]+gg+[a@]+/i, `<img src="https://cdn.discordapp.com/emojis/902742239996936226.webp?size=80" height="16" width="17" style="margin: 1px 0 0 0;"></img>`); let arr = c.split(':'); for (let i = 1; i < arr.length; i += 2) { if (!this.emojiList[arr[i]]) arr = [c]; else arr[i] = `<img src="${this.emojiList[arr[i]]}" height="16" width="18" style="margin: 1px 0 0 0;"></img>`; } let d = a.ui.createElement(`<div class="hud-chat-message"><a href="javascript:void(0);" style="color: red;margin: 0 5px 0 0;display: inline-block;">Block</a><strong> ${b}</strong>: ${arr.join(" ")}<small>${getClock()}</small></div>`); d.children[0].onclick = () => game.ui.components.Chat.blockPlayer(b); a.messagesElem.appendChild(d); a.messagesElem.scrollTop = a.messagesElem.scrollHeight; } new ResizeObserver(game.ui.components.Chat.chatResize.bind(game.ui.components.Chat)).observe(getId("hud-chat")); Game.currentGame.network.emitter.removeListener("PACKET_RPC", Game.currentGame.network.emitter._events.PACKET_RPC[1]); Game.currentGame.network.addRpcHandler("ReceiveChatMessage", game.ui.components.Chat.onMessageReceived.bind(game.ui.components.Chat)); // @Zoom getId('hud').insertAdjacentHTML('beforeend', ` <div class="interaction-wheel"> <a class="hud-zoom-item zoom-reset" onclick="game.zoom.resetZoom();"><i class="fa fa-undo fa-lg" style="font-size: 30px;"></i></a> <a class="hud-zoom-item zoom-up" onclick="game.zoom.zoomOut();"><i class="fa fa-arrow-up fa-2x" style="font-size: 30px;"></i></a> <a class="hud-zoom-item zoom-down" onclick="game.zoom.zoomIn();"><i class="fa fa-arrow-down fa-2x" style="font-size: 30px;"></i></a> <a class="hud-zoom-item zoom-prop">1.0x</a> <a id="zoom-mode">Button</a> <a id="zoom-controls"> <strong>N</strong> to zoom in <br> <strong>M</strong> to zoom out </a> <a id="next-wheel" onclick="game.zoom.toggleZoomOnScroll();"></a> </div> <input id="joinWithPsk" type="tel" placeholder="insert PSK..." class="btn"> `); game.zoom = { dimension: 1, zoomonscroll: false, upd: function() { getClass('zoom-prop')[0].innerText = `${this.dimension.toFixed(1)}x`; this.dimension = Math.max(0.1, this.dimension); const renderer = Game.currentGame.renderer; let canvasWidth = window.innerWidth * window.devicePixelRatio; let canvasHeight = window.innerHeight * window.devicePixelRatio; let ratio = canvasHeight / (1080 * this.dimension); renderer.scale = ratio; renderer.entities.setScale(ratio); renderer.ui.setScale(ratio); renderer.renderer.resize(canvasWidth, canvasHeight); renderer.viewport.width = renderer.renderer.width / renderer.scale + 2 * renderer.viewportPadding; renderer.viewport.height = renderer.renderer.height / renderer.scale + 2 * renderer.viewportPadding; }, onWindowResize: function(e) { if (this.zoomonscroll) { if (e.deltaY > 0) this.dimension += 0.02; else if (e.deltaY < 0) this.dimension -= 0.02; } this.upd(); game.ui.components.PlacementOverlay.onResize?.(); }, zoom: function(val) { this.dimension = val; this.upd(); }, toggleZoomOnScroll: function() { this.dimension -= 0.02; this.zoomonscroll = !this.zoomonscroll; const zoomMode = document.querySelector("#zoom-mode"); const zoomBtns = [...document.getElementsByClassName('hud-zoom-item')]; if (!this.zoomonscroll) { this.resetZoom(); for (let i of zoomBtns) i.classList.remove('tag-is-disabled'); zoomMode.innerText = "Button"; } else { zoomMode.innerText = "Scroll"; for (let i of zoomBtns) i.classList.add('tag-is-disabled'); } }, zoomOut: function() { this.dimension += 1; this.zoom(this.dimension); }, zoomIn: function() { this.dimension -= 1; this.zoom(this.dimension); }, resetZoom: function() { this.dimension = 1; this.zoom(this.dimension); } }; game.zoom.onWindowResize(); window.onresize = game.zoom.onWindowResize.bind(game.zoom); window.onwheel = game.zoom.onWindowResize.bind(game.zoom); /* @Party */ game.ui.components.MenuParty.loaded = false; game.ui.components.MenuParty.serverPopulation = 0; game.ui.components.MenuParty.closedParties = null; game.ui.components.MenuParty.shareKeyLog = null; game.ui.components.MenuParty.partyMenu = getClass("hud-menu-party")[0]; game.ui.components.MenuParty.partyTabs = getClass("hud-party-tabs")[0]; game.ui.components.MenuParty.partyMembers = getClass("hud-party-members")[0]; game.ui.components.MenuParty.partyGrid = getClass("hud-party-grid")[0]; game.ui.components.MenuParty.init = function() { if (this.loaded) return; this.loaded = true; this.partyMembers.style.display = "block"; this.partyGrid.style.display = "none"; const privateTab2 = document.createElement("a"); privateTab2.className = "hud-party-tabs-link"; privateTab2.id = "privateTab2"; privateTab2.innerHTML = "Closed Parties"; this.closedParties = document.createElement("div"); this.closedParties.className = "hud-private hud-party-grid"; this.closedParties.id = "privateHud2"; this.closedParties.style.display = "none"; this.partyTabs.appendChild(privateTab2); this.partyMenu.insertBefore(this.closedParties, getClass("hud-party-actions")[0]); const privateTab = document.createElement("a"); privateTab.className = "hud-party-tabs-link"; privateTab.id = "privateTab"; privateTab.innerHTML = "Key Logs"; this.shareKeyLog = document.createElement("div"); this.shareKeyLog.className = "hud-private hud-party-grid"; this.shareKeyLog.id = "privateHud"; this.shareKeyLog.style.display = "none"; this.partyTabs.appendChild(privateTab); this.partyMenu.insertBefore(this.shareKeyLog, getClass("hud-party-actions")[0]); privateTab.addEventListener("click", e => { for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) { menu.style.display == "block" && (menu.style.display = "none"); } for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link"; privateTab.className = "hud-party-tabs-link is-active"; this.shareKeyLog.style.display = "block"; }) privateTab2.addEventListener("click", e => { for (let menu of [this.partyMembers, this.partyGrid, this.closedParties, this.shareKeyLog]) { menu.style.display == "block" && (menu.style.display = "none"); } for (let i of getClass("hud-party-tabs-link")) i.className = "hud-party-tabs-link"; privateTab2.className = "hud-party-tabs-link is-active"; this.closedParties.style.display = "block"; }) getClass("hud-party-tabs-link")[0].addEventListener("click", e => { this.shareKeyLog.style.display = "none"; privateTab.className = "hud-party-tabs-link"; this.closedParties.style.display = "none"; privateTab2.className = "hud-party-tabs-link"; }) getClass("hud-party-tabs-link")[1].addEventListener("click", e => { this.shareKeyLog.style.display = "none"; privateTab.className = "hud-party-tabs-link"; this.closedParties.style.display = "none"; privateTab2.className = "hud-party-tabs-link"; }) } game.ui.components.MenuParty.onSetPartyList = function(parties) { this.serverPopulation = 0; for (let party of parties) this.serverPopulation += party.memberCount; document.getElementsByClassName("hud-party-server")[0].innerHTML = `${this.serverPopulation}/32<small id="serverRegion"></small>`; } game.ui.components.MenuParty.onPartyShareKey = function(e) { const psk = e.partyShareKey, lnk = `https://zombs.io/#/${game.options.serverId}/${psk}/`; this.shareKeyLog.innerHTML += ` <div style="display:inline-block;margin:10px 5px 0;"> <li> <strong style="cursor: pointer;" onclick="game.network.sendRpc({ name: 'JoinPartyByShareKey', partyShareKey: '${psk}' });">${psk}</strong> - <a href="${lnk}" target="_blank" color="purple">[Link]</a> </li> </div> <br /> `; } game.ui.components.MenuParty.update = function () { var parties = this.ui.getParties(); var playerIsLeader = this.ui.getPlayerPartyLeader(); var playerPartyData = parties[this.ui.getPlayerPartyId()]; var playerPartyMembers = this.ui.getPlayerPartyMembers(); var serverId = this.ui.getOption('serverId'); var staleElems = {}; var availableParties = 0; this.clonedPartyElems ||= {}; this.closedGridElem ||= getId("privateHud2"); for (var partyId in this.partyElems) { staleElems[partyId] = true; } for (var partyId in parties) { var partyData = parties[partyId]; var partyElem = this.partyElems[partyId]; var partyNameSanitized = window.filterXSS(partyData.partyName); delete staleElems[partyId]; if (!this.partyElems[partyId]) { partyElem = this.ui.createElement("<div class=\"hud-party-link\"></div>"); this.clonedPartyElems[partyId] = this.ui.createElement("<div class=\"hud-party-link\"></div>"); this.partyElems[partyId] = partyElem; this.gridElem.appendChild(partyElem); this.closedGridElem.appendChild(this.clonedPartyElems[partyId]); partyElem.addEventListener('click', this.onPartyJoinRequestHandler(partyData.partyId).bind(this)); } if (partyData.isOpen) { partyElem.style.display = 'block'; this.clonedPartyElems[partyId].style.display = "none"; availableParties++; } else { partyElem.style.display = 'none'; this.clonedPartyElems[partyId].style.display = "block"; } if (this.ui.getPlayerPartyId() === partyData.partyId) { partyElem.classList.add('is-active'); partyElem.classList.remove('is-disabled'); this.clonedPartyElems[partyId].classList.add('is-active'); this.clonedPartyElems[partyId].classList.remove('is-disabled'); } else if (partyData.memberCount === this.maxPartySize) { partyElem.classList.remove('is-active'); partyElem.classList.add('is-disabled'); this.clonedPartyElems[partyId].classList.remove('is-active'); this.clonedPartyElems[partyId].classList.add('is-disabled'); } else { partyElem.classList.remove('is-active'); partyElem.classList.remove('is-disabled'); this.clonedPartyElems[partyId].classList.remove('is-active'); this.clonedPartyElems[partyId].classList.remove('is-disabled'); } partyElem.innerHTML = "<strong>" + partyNameSanitized + "</strong><small>id: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span>"; this.clonedPartyElems[partyId].innerHTML = "<strong>" + partyNameSanitized + "</strong><small>id: " + partyData.partyId + "</small> <span>" + partyData.memberCount + "/" + this.maxPartySize + "</span>"; } for (var partyId in staleElems) { if (!this.partyElems[partyId]) { continue; } this.partyElems[partyId].remove(); this.clonedPartyElems[partyId].remove(); delete this.partyElems[partyId]; delete this.clonedPartyElems[partyId]; } for (var i in this.memberElems) { this.memberElems[i].remove(); delete this.memberElems[i]; } for (var i in playerPartyMembers) { var playerName = window.filterXSS(playerPartyMembers[i].displayName); var memberElem = this.ui.createElement( "<div class=\"hud-member-link\">\n <strong>" + playerName + "</strong>\n <small>" + (playerPartyMembers[i].isLeader === 1 ? 'Leader' : 'Member') + "</small>\n <div class=\"hud-member-actions\">\n <a class=\"hud-member-can-sell btn" + (!playerIsLeader || playerPartyMembers[i].isLeader === 1 ? ' is-disabled' : '') + (playerPartyMembers[i].canSell === 1 ? ' is-active' : '') + "\"><span class=\"hud-can-sell-tick\"></span> Can sell buildings</a>\n <a class=\"hud-member-kick btn btn-red" + (!playerIsLeader || playerPartyMembers[i].isLeader === 1 ? ' is-disabled' : '') + "\">Kick</a>\n </div>\n </div>" ); this.membersElem.appendChild(memberElem); this.memberElems[i] = memberElem; if (playerIsLeader && playerPartyMembers[i].isLeader === 0) { var kickElem = memberElem.querySelector('.hud-member-kick'); var canSellElem = memberElem.querySelector('.hud-member-can-sell'); kickElem.addEventListener('click', this.onPartyMemberKick(i).bind(this)); canSellElem.addEventListener('click', this.onPartyMemberCanSellToggle(i).bind(this)); } } if (availableParties > 0) { this.gridEmptyElem.style.display = 'none'; } else { this.gridEmptyElem.style.display = 'block'; } if (!playerPartyData) { this.tagInputElem.setAttribute('disabled', 'true'); this.tagInputElem.value = ''; this.shareInputElem.setAttribute('disabled', 'true'); this.shareInputElem.value = ''; this.visibilityElem.classList.add('is-disabled'); return; } if (document.activeElement !== this.tagInputElem) { this.tagInputElem.value = playerPartyData.partyName; } if (playerIsLeader) { this.tagInputElem.removeAttribute('disabled'); } else { this.tagInputElem.setAttribute('disabled', 'true'); } this.shareInputElem.removeAttribute('disabled'); this.shareInputElem.value = 'https://zombs.io/#/' + serverId + '/' + this.ui.getPlayerPartyShareKey(); if (playerIsLeader) { this.visibilityElem.classList.remove('is-disabled'); } else { this.visibilityElem.classList.add('is-disabled'); } if (playerPartyData.isOpen) { this.visibilityElem.classList.remove('is-private'); this.visibilityElem.innerText = 'Public'; } else { this.visibilityElem.classList.add('is-private'); this.visibilityElem.innerText = 'Private'; } } getClass("hud-party-actions")[0].insertAdjacentHTML("afterend", ` <div class="partydiv" style="text-align: center"> <button class="btn btn-red" style="width: 275.5px;margin: 10px 0 0 3px;box-shadow: none;" onclick="Game.currentGame.network.sendRpc({name: 'LeaveParty'});">Leave</button> </div>`); game.ui.components.MenuParty.init(); game.network.addRpcHandler("PartyShareKey", (e) => game.ui.components.MenuParty.onPartyShareKey(e)); game.network.addRpcHandler("SetPartyList", (e) => game.ui.components.MenuParty.onSetPartyList(e)); /* @Settings @ModMenu */ getId('hud-menu-settings').innerHTML = ` <a class="hud-menu-close" onclick="document.getElementById('hud-menu-settings').style.display = 'none';"></a> <h3>Advanced</h3> <div id="select-page"> <button id="back-page" class="no-bg"><i class="fas fa-arrow-left"></i></button> <span id="page-name">-</span> <button id="forward-page" class="no-bg"><i class="fas fa-arrow-right"></i></button> </div> <div class="hint-controls"></div> <div class="hud-settings-grid" page="0"></div> `; getClass('hud-settings-grid')[0].innerHTML = ` <div class="hud-settings-page" id="page0"> <div class="hud-settings-options"></div> <div class="hud-settings-more"></div> </div> <div class="hud-settings-page" id="page1"> <div class="hud-settings-options"></div> <div class="hud-settings-more"></div> </div> <div class="hud-settings-page" id="page2"> <div class="hud-settings-options"></div> <div class="hud-settings-more"></div> </div> <div class="hud-settings-page" id="page3"> <!-- <div class="hud-settings-options"></div> <div class="hud-settings-more"></div> --> <span>Coming soon...</span> </div> <div class="hud-settings-page" id="page4"> <div class="hud-settings-options"></div> <div class="hud-settings-more"></div> </div> `; const hint_enum = { 0: `<li><strong>Shift + 1</strong> [!] toggles Wall Block.</li> <li><strong>Comma</strong> [,] toggles Rebuilder.</li> <li><strong>Period</strong> [.] toggles Auto Upgrade.</li>`, 1: `<li><strong>C</strong> toggles quick join via PSK input.</li> <li><strong>G</strong> toggles zoom menu.</li> <li><strong>Dash</strong> [-] toggles local info indicators.</li> <li><strong>Equal</strong> [=] toggles Auto Bow.</li> <li><strong>Semi-colon</strong> [;] deletes your pet.</li> <li><strong>Back-tick</strong> ['] revives your pet.</li>`, // anti tiến bịp, 2: ``, 3: ``, 4: `<li><strong>?</strong> toggles Screenshot Mode.</li> <li><strong>~</strong> marks your position.</li>` }; const pageName_enum = { 0: 'Build', 1: 'Player', 2: 'Visual', 3: 'Clone', 4: 'Misc.', }; /* const optionElem_enum = { name: 'h2', description: 'span', } */ const menu = { page0: { AHRC: { name: `AHRC`, description: `Automatically harvests resources.`, more: null }, rebuild: { name: `Auto Rebuilder`, description: `Automatically rebuilds dead towers.`, more: null, onCallback: () => { game.rebuilder.saveTowers(); }, offCallback: () => { game.rebuilder.reset(); }, }, autoUpgrade: { name: `Auto Upgrader`, description: `Automatically upgrades towers.`, more: null }, wallBlock: { name: `Wall Block`, description: `Allows you to place mulitple walls at once.`, more: { html: ` <strong>Change the size of the block that will be placed.</strong> <span>Default value is 5x5, maximum is 15x15 (cells).</span> <div style="display: flex;align-items: center;justify-content: space-between;"> Width: <input id="blockX" type="number" placeholder="w" min="3" max="15" value="3" class="btn" style="width: 20%"> Height: <input id="blockY" type="number" placeholder="h" min="3" max="15" value="3" class="btn" style="width: 20%"> </div> `, functions: () => {}, }, }, baseSaver: { name: "Base Saver", description: `Manage all your saved bases here.`, more: { html: ` <div id="base-container"></div> <div id="base-management" style="display: none;"> <br><a href="javascript:void(0);" id="return-to-manager" style="color: var(--light-hover-btn);"><i class="fa fa-angle-left"></i> Go back to base manager</a> <br><h2>Design</h2><hr /> <input id="target-base-design" type="tel" placeholder="Base string" class="btn"> <button id="clear-target-design" class="no-bg underline-red" style="width: calc(50% - 5px);" onclick="document.getElementById('target-base-design').value = '';">Clear</button> <button id="view-target-design" class="no-bg underline-white" style="width: calc(50% - 5px);margin: 0 0 5px 5px;">View</button> <button id="encode-target-design" class="btn-important" style="width: calc(50% - 5px);">Encode</button> <button id="build-design" class="btn-important" style="width: calc(50% - 5px);margin: 0 0 5px 5px;">Build</button> <br></br> <h2>Info</h2><hr /> <input id="target-base-name" type="tel" placeholder="Base name" class="btn" maxlength="20"> <input id="target-base-description" type="tel" placeholder="Base description" class="btn" maxlength="40"> <button id="save-config" class="btn-important" onclick="window.saveCurrentBaseConfig();">Save</button> </div> `, functions: () => { localStorage.totalSlots ||= 2; getId("return-to-manager").onclick = () => document.querySelector("#more-baseSaver").click(); window.createBaseSlot = function() { const oldTotalSlots = parseInt(localStorage.totalSlots); const nextItem = oldTotalSlots + 1; localStorage.totalSlots = nextItem; localStorage[`baseslot${nextItem}`] = '|||'; document.querySelector("#more-baseSaver").click(); }; window.isSlotEmpty = function(index) { const baseData = localStorage[`baseslot${index}`]?.split("|"); return !!baseData?.[0]; }; window.createBaseSlot = function() { const oldTotalSlots = parseInt(localStorage.totalSlots); const nextItem = oldTotalSlots + 1; localStorage.totalSlots = nextItem; localStorage[`baseslot${nextItem}`] = '|||'; document.querySelector("#more-baseSaver").click(); } window.isSlotEmpty = function(index) { const baseData = localStorage[`baseslot${index}`]?.split("|"); return !!baseData?.[0]; }; window.saveCurrentBaseConfig = function() { const [design, title, description, date] = [...document.querySelectorAll("#target-base-design, #target-base-name, #target-base-description"), new Date().toLocaleDateString()]; const baseManagement = getId('base-management'); const currentBaseItem = baseManagement.getAttribute('current-item'); localStorage[`baseslot${currentBaseItem}`] = `${design.value}|${title.value}|${description.value}|${date}`; return void game.ui.components.PopupOverlay.showHint('Current base configuration saved.'); }; }, bind: () => { const baseContainer = getId('base-container'); const baseManagement = getId('base-management'); baseContainer.innerHTML = ''; baseManagement.style.display = "none"; for (let i = 1; i < parseInt(localStorage.totalSlots) + 1; i++) { const baseItem = document.createElement('div'); const baseData = localStorage[`baseslot${i}`]?.split("|"); const baseId = genUUID(); baseData?.[1] && (baseData[1] = window.filterXSS(baseData[1])); baseData?.[2] && (baseData[2] = window.filterXSS(baseData[2])); baseItem.classList.add('base-card'); baseItem.id = `base-item-${i}`; baseItem.setAttribute('item-base', i); baseItem.innerHTML = ` <strong></strong> <span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;"></span> <span style="color: rgba(255, 255, 255, 0.4);font-size: 13px;display: flex;justify-content: flex-end;transform: translate(0px, -40px);"></span> `; const [title, description, date] = baseItem.children; title.innerText = baseData?.[1] || "Unoccupied"; description.innerText = baseData?.[2] || "-"; date.innerText = baseData?.[3] || ""; baseItem.onclick = function() { const [designField, titleField, descriptionField] = [...document.querySelectorAll("#target-base-design, #target-base-name, #target-base-description")]; designField.value = baseData?.[0] || ""; titleField.value = baseData?.[1] || ""; descriptionField.value = baseData?.[2] || ""; getId("encode-target-design").onclick = game.builder.recordBase.bind(game.builder); getId("view-target-design").onclick = () => game.ui.components.PlacementOverlay.showOverlay(designField.value, 10000); baseManagement.setAttribute('current-item', i); for (let otherItem = 1; otherItem < parseInt(localStorage.totalSlots) + 1; otherItem++) { const item = getId(`base-item-${otherItem}`); const isThisItem = item.getAttribute('item-base') == i; if (isThisItem) continue; item.style.display = "none"; }; baseItem.style.transform = 'translate(0px, 306px)'; getId('add-base-slot').style.display = "none"; baseManagement.style.display = "block"; getId("build-design").onclick = function() { game.ui.components.PopupOverlay.showConfirmation("Are you sure you want to build base?", 5000, function() { game.builder.buildBase(designField.value); }); } }; baseContainer.appendChild(baseItem); } const addItem = document.createElement('div'); addItem.classList.add('base-card'); addItem.id = "add-base-slot"; addItem.innerHTML = ` <strong style="position: absolute;top: 20px;left: 40px;opacity: 0.4;"><i class="fas fa-plus"></i></strong> <span style="color: rgba(255, 255, 255, 0.4);display: flex;justify-content: flex-end;position: absolute;left: 65px;top: 20px;">Add another base slot</span> `; addItem.onclick = window.createBaseSlot; baseContainer.appendChild(addItem); }, }, }, }, page1: { chatSpam: { name: `Chat Spammer`, description: `Annoys other players with messages.`, more: { html: ` <strong>Input the text that you want to spam.</strong> <span>If no text is inputted, random messages with be sent.</span> <input id="chat-spam-input" placeholder="Spam text here..." /> `, functions: () => { const spamInputElem = getId("chat-spam-input"); spamInputElem.oninput = game.spam.onchange.bind(game.spam); } }, onCallback: () => { game.spam.start(); }, offCallback: () => { game.spam.stop(); }, }, autoAim: { name: `Auto Aim`, description: "Aims at the nearest player.", more: null }, autoHeal: { name: "Auto Heal", description: "Heals your player/pet automatically.", more: { html: ` <strong>Define the health percentage that the auto heal will kick in if below it.</strong> <span>Default value is 25%.</span> <input id="auto-heal-threshold" type="number" placeholder="Enter a valid percentile here..." min="1" max="100" value="25" /> `, functions: () => {}, } }, frss: { name: "Exact Resource Counter", description: `"De-truncate" your resource counter.`, more: null, }, }, page2: { ground: { name: "Render Ground", description: "Toggles rendering of the ground.", more: null, onCallback: () => { game.renderer.ground.setVisible(true); }, offCallback: () => { game.renderer.ground.setVisible(false); }, }, npcs: { name: "Render NPCs", description: "Toggles rendering of NPCs.", more: null, onCallback: () => { game.renderer.npcs.setVisible(true); }, offCallback: () => { game.renderer.npcs.setVisible(false); }, }, projectiles: { name: "Render Projectiles", description: "Toggles rendering of projectiles.", more: null, onCallback: () => { game.renderer.projectiles.setVisible(true); }, offCallback: () => { game.renderer.projectiles.setVisible(false); }, }, scenery: { name: "Render Environment", description: "Toggles rendering of the environment.", more: null, onCallback: () => { game.renderer.scenery.setVisible(true); }, offCallback: () => { game.renderer.scenery.setVisible(false); }, }, groupingGrid: { name: "Grouping Grid", description: "Warning: conflicts with ground rendering.", more: null, onCallback: () => { game.renderer.ground.attachments[0].attachments[1].setAlpha(0.625); game.renderer.ground.attachments[0].attachments[1].setScale(200 / 48); game.renderer.ground.attachments[0].attachments[1].sprite.width /= 200 / 48; game.renderer.ground.attachments[0].attachments[1].sprite.height /= 200 / 48; }, offCallback: () => { game.renderer.ground.attachments[0].attachments[1].setAlpha(1); game.renderer.ground.attachments[0].attachments[1].setScale(1); game.renderer.ground.attachments[0].attachments[1].sprite.width *= 200 / 48; game.renderer.ground.attachments[0].attachments[1].sprite.height *= 200 / 48; }, } }, /* page3: {}, */ page4: { autoUpTowers: { name: "Building Support", description: "Auto-upgrades low-health towers.", more: { html: ` <strong>Define the health percentage to upgrade buildings when their health is below it.</strong> <span>Default value is 20%.</span> <input id="auto-tower-upgrade-threshold" type="number" placeholder="Enter a valid percentile here..." min="1" max="99" value="20" /> `, functions: () => {}, } } }, }; function refreshMore(page) { const container = document.querySelector("#" + page + " > div.hud-settings-more"); for (let children of container.children) { children.style.display = "none"; } } function refreshPage(pageState, page) { for (let i = 0; i < 5; i++) getId(`page${i}`).style.display = "none"; }; function setPage(page) { const pageState = page; switch(page) { case "forward": page = parseInt(getClass('hud-settings-grid')[0].getAttribute('page')) + 1; break; case "backwards": page = parseInt(getClass('hud-settings-grid')[0].getAttribute('page')) - 1; break; } refreshPage(pageState, page); if (page < 0) page = 4; if (page > 4) page = 0; getId(`page${page}`).style.display = "flex"; getId('page-name').innerText = pageName_enum[page]; getClass('hint-controls')[0].innerHTML = hint_enum[page]; getClass('hud-settings-grid')[0].setAttribute('page', page); }; setPage('0'); getId('back-page').addEventListener('click', () => setPage("backwards")); getId('forward-page').addEventListener('click', () => setPage("forward")); // @Misc. Game.currentGame.world.removeEntity = function(t) { if (["Tree", "Stone", "NeutralCamp"].indexOf(this.entities[t].fromTick.model) > -1) return; this.renderer.remove(this.entities[t]); const model = this.entities[t].currentModel; if (Game.currentGame.getModelEntityPooling(model.modelName)) { model.reset(); this.modelEntityPool[model.modelName].push(model); } this.entityGrid.removeEntity(parseInt(t)); delete this.entities[t]; }; const toolbar_enum = { "Pickaxe": { index: 0, hasNextTier: true }, "Spear": { index: 1, hasNextTier: true }, "Bow": { index: 2, hasNextTier: true }, "Bomb": { index: 3, hasNextTier: true }, "HealthPotion": { index: 4, hasNextTier: false }, "PetHealthPotion": { index: 5, hasNextTier: false }, }; getClass('hud-top-center')[0].insertAdjacentHTML('afterbegin', ` <div class="hud-center-toolbar"> ${Object.keys(toolbar_enum).map(itemName => { return `<a class="hud-center-toolbar-item" data-item="${itemName}" data-tier="1"></a>`; }).join("\n")} </div> `); [...document.querySelector("#hud > div.hud-top-center > div").children].forEach(elem => { elem.onclick = () => { const itemName = elem.getAttribute("data-item"); const itemTier = elem.getAttribute("data-tier"); game.network.sendRpc({name: "BuyItem", itemName, tier: parseInt(itemTier)}); }; }); game.network.addRpcHandler("SetItem", ({itemName, tier}) => { if (Object.keys(toolbar_enum).indexOf(itemName) > -1) { const { index, hasNextTier } = toolbar_enum[itemName]; if (!hasNextTier) return; document.querySelector("#hud > div.hud-top-center > div").children[index].classList[tier == 8 ? "add" : "remove"]("is-disabled"); document.querySelector("#hud > div.hud-top-center > div").children[index].setAttribute("data-tier", tier + 1); }; }); /* @Functions */ // @Options game.options.options = { autoBow: false, getRSS: false, AHRC: false, rebuild: false, autoUpgrade: false, heal: true, revive: true, frss: false, chatSpam: false, autoAim: false, wallBlock: false, autoHeal: true, ground: true, npcs: true, projectiles: true, scenery: true, groupingGrid: false, autoUpTowers: false, } // @Marker game.markers = { currentIndex: 0, allMarkers: [], placeMarker: function({x, y, id, timeout, shouldIndicateIndex}) { id ||= Math.random(); shouldIndicateIndex && (this.currentIndex++); const markerLeft = parseInt(Math.round(x / game.world.getWidth() * 100)) - 4; const markerTop = parseInt(Math.round(y / game.world.getHeight() * 100)) - 14; const markerElem = document.createElement("div"); markerElem.style.left = `${markerLeft}%`; markerElem.style.top = `${markerTop}%`; markerElem.style.display = "block"; markerElem.style.color = "white"; markerElem.style.position = "absolute"; markerElem.classList.add("map-display"); markerElem.id = id; markerElem.innerHTML = `<i class='fa fa-map-marker'>${shouldIndicateIndex ? this.currentIndex : ""}</i>`; getId("hud-map").insertAdjacentElement("beforeend", markerElem); this.allMarkers.push({x, y}); timeout && setTimeout(() => { getId(`${id}`).remove(); }, 240000); } } // @RSSOverhead game.rssOverhead = { allowedRSS: true, assignOldTick: function(player, playerTick) { const [wood_1, stone_1, gold_1, token_1, px_1, py_1, info] = playerTick; player.targetTick.oldWood = wood_1; player.targetTick.oldStone = stone_1; player.targetTick.oldGold = gold_1; player.targetTick.oldToken = token_1; player.targetTick.oldPX = px_1; player.targetTick.oldPY = py_1; player.targetTick.info = info; player.targetTick.name = player.targetTick.info; }, onTick: function(entities) { const options = game.options.options; if (options.getRSS) !this.allowedRSS && (this.allowedRSS = true); if (options.getRSS || this.allowedRSS) { for (let uid in entities) { const player = game.world.entities[uid]; if (!!player?.fromTick?.name) { let wood_1 = counter(player.targetTick.wood); let stone_1 = counter(player.targetTick.stone); let gold_1 = counter(player.targetTick.gold); let token_1 = counter(player.targetTick.token); let px_1 = counter(player.targetTick.position.x); let py_1 = counter(player.targetTick.position.y); let timeout_1 = player.targetTick.isPaused ? "On Timeout" : ""; if (options.getRSS && !player.targetTick.oldName) { player.targetTick.oldName = player.targetTick.name; let info = ` ${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()} UID: ${player.targetTick.uid} W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1} partyId: ${Math.round(player.targetTick.partyId)} timeDead: ${msToTime(player.targetTick.timeDead)} ${timeout_1} `; this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]); } if (!options.getRSS && player.targetTick.oldName) { player.targetTick.info = player.targetTick.oldName; player.targetTick.name = player.targetTick.info; player.targetTick.oldName = null; } if (options.getRSS) { if (player.targetTick.oldGold !== gold_1 || player.targetTick.oldWood !== wood_1 || player.targetTick.oldStone !== stone_1 || player.targetTick.oldToken !== token_1 || player.targetTick.oldPX !== px_1 || player.targetTick.oldPY !== py_1) { let info = ` ${window.filterXSS(player.targetTick.oldName)}; score: ${player.targetTick.score.toLocaleString()} UID: ${player.targetTick.uid} W: ${wood_1}, S: ${stone_1}, G: ${gold_1}, T: ${token_1} partyId: ${Math.round(player.targetTick.partyId)} timeDead: ${msToTime(player.targetTick.timeDead)} ${timeout_1} `; this.assignOldTick(player, [wood_1, stone_1, gold_1, token_1, px_1, py_1, info]); } } } } } if (!options.getRSS) this.allowedRSS = false; }, } // @AHRC game.ahrc = { checkedHarvesters: new Set(), workingHarvesters: new Set(), onTick: function() { const options = game.options.options; if (options.AHRC) { for (let uid in game.world.entities) { const entity = game.world.entities[uid]; if (entity.targetTick.model == "Harvester" && entity.targetTick.partyId == game.ui.playerPartyId && game.ui.playerTick.gold > 0.69) { if (this.checkedHarvesters.has(uid)) { if (entity.fromTick.stone !== entity.targetTick.stone || entity.fromTick.wood !== entity.targetTick.wood) { this.workingHarvesters.add(uid); }; } else { this.checkedHarvesters.add(uid); game.network.sendRpc({name: "AddDepositToHarvester", uid: parseInt(uid), deposit: 0.69}); }; }; if (this.workingHarvesters.has(uid)) { const amount = entity.fromTick.tier * 0.05 - 0.02; game.network.sendRpc({name: "AddDepositToHarvester", uid: parseInt(uid), deposit: amount}); game.network.sendRpc({name: "CollectHarvester", uid: parseInt(uid)}); }; }; } } } // @Rebuilder game.rebuilder = { savedTowers: new Map(), shouldBeReplaced: [], goldStash: null, reset: function() { this.savedTowers = new Map(); }, saveTowers: function() { for (let i in game.ui.buildings) { const {x, y, type} = game.ui.buildings[i]; this.savedTowers.set(parseInt(i), {x, y, type}); } }, onLocalBuilding: function(buildings) { const options = game.options.options; const allBuildings = Object.values(game.ui.buildings); this.goldStash = allBuildings.find(building => building.type == "GoldStash"); if (options.rebuild) { for (let i in buildings) { const {dead, uid, x, y, type, tier} = buildings[i]; if (dead === 1) { if (this.savedTowers.get(uid) !== undefined) { this.shouldBeReplaced.push({x, y, type}); } } else { const oldBuilding = getByValue(this.savedTowers, {x, y, type}); if (oldBuilding) { this.savedTowers.set(parseInt(uid), {x, y, type}); this.shouldBeReplaced = this.shouldBeReplaced.filter(e => !equal(e, {x, y, type})); } } } } }, onTick: function(entities) { const options = game.options.options; if (options.rebuild && this.goldStash) { for (let i = this.shouldBeReplaced.length - 1; i >= 0; i--) { const deadTower = this.shouldBeReplaced[i]; const {x, y, type} = deadTower; game.network.sendRpc({name: "MakeBuilding", type, x, y, yaw: 0}); } } }, }; // @Builder game.builder = { towerCodes: ["Wall", "Door", "SlowTrap", "ArrowTower", "CannonTower", "MeleeTower", "BombTower", "MagicTower", "GoldMine", "Harvester"], buildBase: function(design) { const goldStash = game.rebuilder.goldStash; if (typeof design !== "string") throw new Error("Argument must be given as a string."); if (goldStash === undefined) throw new Error("You must have a gold stash to be able to use this."); const towers = design.split(";"); for (let towerStr of towers) { const tower = towerStr.split(","); if (tower[0] === "") continue; if (tower.length < 4) throw new Error(`${JSON.stringify(tower)} contains an issue that must be fixed before this design can be replicated.`); Game.currentGame.network.sendRpc({ name: "MakeBuilding", type: this.towerCodes[parseInt(tower[0])], x: goldStash.x - parseInt(tower[1]), y: goldStash.y - parseInt(tower[2]), yaw: parseInt(tower[3]) }); }; }, recordBase: function() { const goldStash = game.rebuilder.goldStash; let baseStr = ""; for (let i in game.ui.buildings) { const building = game.ui.buildings[i]; if (this.towerCodes.indexOf(building.type) < 0) continue; let yaw = 0; if (["Harvester", "MeleeTower"].includes(building.type)) { if (game.world.entities[building.uid] !== undefined) yaw = game.world.entities[building.uid].targetTick.yaw; } baseStr += `${this.towerCodes.indexOf(building.type)},${goldStash.x - building.x},${goldStash.y - building.y},${yaw};`; } getId('target-base-design').value = baseStr; } }; // @AutoAim game.autoAim = { targets: [], onTick: function() { const options = game.options.options; if (options.autoAim) { this.targets = []; const entities = Object.values(game.world.entities); for (let entity of entities) { if (entity.fromTick.model == "GamePlayer" && entity.targetTick.partyId !== game.ui.playerPartyId && entity.fromTick.dead == 0) { this.targets.push(entity.fromTick); }; }; if (this.targets.length > 0) { const myPos = game.ui.playerTick.position; this.targets.sort((a, b) => { return measureDistance(myPos, a.position) - measureDistance(myPos, b.position); }); const target = this.targets[0]; let reversedAim = game.inputPacketCreator.screenToYaw((target.position.x - myPos.x) * 100, (target.position.y - myPos.y) * 100); game.inputPacketCreator.lastAnyYaw = reversedAim; game.network.sendPacket(3, {mouseMoved: reversedAim}); } }; } }; // @Buildings game.ui.components.PlacementOverlay.showOverlay = function (design, timeout) { this.buildingId && this.cancelPlacing(); const goldStash = game.rebuilder.goldStash; if (typeof design !== "string") throw new Error("Argument must be given as a string."); if (goldStash === null) throw new Error("You must have a gold stash to be able to use this."); this.overlayEntities && (this.overlayEntities.length > 0 && this.overlayEntities.map(e => game.renderer.ui.removeAttachment(e))); this.overlayEntities = []; this.overlayDesign = design; this.isShowingOverlay = true; game.renderer.follow(game.world.entities[goldStash.uid]); setTimeout(() => { const towers = design.split(";"), schema = this.ui.getBuildingSchema(); for (let towerStr of towers) { const towerData = towerStr.split(","); const [type, xWorld, yWorld, yaw] = towerData; const towerLength = towerData.length if (type === "") continue; if (towerLength.length < 4) throw new Error(`${JSON.stringify(towerLength)} contains an issue that must be fixed before this design can be replicated.`); const buildingType = schema[game.builder.towerCodes[parseInt(type)]], placeholderEntity = Game.currentGame.assetManager.loadModel(buildingType.modelName, {}), { x, y } = game.renderer.worldToUi(goldStash.x - parseInt(xWorld), goldStash.y - parseInt(yWorld)); placeholderEntity.setAlpha(0.5); placeholderEntity.setRotation(parseInt(yaw)); placeholderEntity.setPosition(x, y); Game.currentGame.renderer.ui.addAttachment(placeholderEntity); this.overlayEntities.push(placeholderEntity); } timeout && setTimeout(game.ui.components.PlacementOverlay.hideOverlay.bind(this), timeout); }, 50); } game.ui.components.PlacementOverlay.hideOverlay = function() { for (let entity of this.overlayEntities) game.renderer.ui.removeAttachment(entity); game.renderer.follow(game.world.entities[game.world.myUid]); this.isShowingOverlay = false; this.overlayDesign = null; } game.ui.components.PlacementOverlay.onResize = function() { this.isShowingOverlay && game.ui.components.PlacementOverlay.showOverlay(this.overlayDesign); } game.ui.components.BuildingOverlay.createResourceCostString = function (schema, schemaTier, amountOfBuildings) { void 0 === schemaTier && (schemaTier = 0x1); void 0 === amountOfBuildings && (amountOfBuildings = 0x1); var totalCost = [], resources = { 'wood': `wood`, 'stone': `stone`, 'gold': 'gold', 'token': 'tokens' }, playerTick = Game.currentGame.ui.getPlayerTick(); for (var resource in resources) { var resourceCost = resource + `Costs`; if (schema[resourceCost] && schema[resourceCost][schemaTier - 1]) { var currentTotalCost = schema[resourceCost][schemaTier - 1] * amountOfBuildings, canAfford = playerTick && playerTick[resource] >= currentTotalCost; canAfford ? totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`) : totalCost.push(`<span class="hud-resource-` + resources[resource] + ` hud-resource-low">` + currentTotalCost.toLocaleString() + '\x20' + resources[resource] + `</span>`); } } return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">Free</span>`; } game.ui.components.BuildingOverlay.createResourceRefundString = function (buildingType, buildingSchema, tier) { void 0 === tier && (tier = 1); var totalCost = [], buildingsByTier = {}, buildings = Object.values(game.ui.buildings).filter(e => e.type == buildingType), resources = { 'wood': `wood`, 'stone': `stone`, 'gold': `gold`, 'token': 'tokens' }; for (let building of buildings) { buildingsByTier[building.tier] ||= 0; buildingsByTier[building.tier]++; } for (var resource in resources) { var resourceCost = resource + `Costs`; if (buildingSchema[resourceCost]) { var totalTierCost = 0; if (this.shouldUpgradeAll) { for (let i = 1; i <= tier; i++) { totalTierCost = Math.floor( buildingSchema[resourceCost].slice(0, i) .reduce((prev, curr) => prev + curr, 0) / 2 ) * buildingsByTier[i]; } } else totalTierCost = Math.floor(buildingSchema[resourceCost].slice(0, tier).reduce((prev, curr) => prev + curr, 0) / 2); totalTierCost && totalCost.push('<span\x20class=\x22hud-resource-' + resources[resource] + '\x22>' + totalTierCost.toLocaleString() + '\x20' + resources[resource] + `</span>`); } } return totalCost.length > 0 ? totalCost.join(',\x20') : `<span class="hud-resource-free">None</span>`; } game.ui.components.BuildingOverlay.sellBuilding = function () { if (this.buildingUid) { if ('GoldStash' == this.buildingId) { game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings?`, 5000, function() { sellAll(); }); return this.stopWatching(); } if (this.shouldUpgradeAll) { const id = this.buildingId; game.ui.components.PopupOverlay.showConfirmation(`Are you sure you want to delete all buildings of this type?`, 5000, function() { sellAllByType(id); }); } else Game.currentGame.network.sendRpc({name: 'DeleteBuilding', uid: this.buildingUid}); } } game.ui.components.BuildingOverlay.startWatching = function(buildingId) { this.buildingUid && this.stopWatching(); let buildings = this.ui.getBuildings(), building = buildings[buildingId]; if (!building) return; this.buildingUid = buildingId; this.buildingId = building.type; this.buildingTier = building.tier; let schema = this.ui.getBuildingSchema(), buildingSchema = schema[this.buildingId]; if ('GoldStash' == this.buildingId) { var world = Game.currentGame.world, cellSize = world.entityGrid.getCellSize(); this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', { 'width': this.maxStashDistance * cellSize * 2, 'height': this.maxStashDistance * cellSize * 2 }); Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator); } else { buildingSchema.rangeTiers && ( this.rangeIndicator = game.assetManager.loadModel('RangeIndicatorModel', { 'isCircular': true, 'radius': buildingSchema.rangeTiers[this.buildingTier - 1] * 0.57071 }), Game.currentGame.renderer.ground.addAttachment(this.rangeIndicator) ); }; this.componentElem.innerHTML = `<div class="hud-tooltip-building"> <h2>` + buildingSchema.name + `</h2> <h3>Tier <span class="hud-building-tier">` + this.buildingTier + `</span> Building</h3> <div class="hud-tooltip-health"> <span class="hud-tooltip-health-bar" style="width:100%;"></span> </div> <div class="hud-tooltip-body"> <div class="hud-building-stats"></div> <p class="hud-building-actions"> <span class="hud-building-dual-btn"> <a class="btn btn-purple hud-building-deposit">Refuel</a> <a class="btn btn-gold hud-building-collect">Collect</a> </span> <a class="btn btn-gold hud-building-upgrade">Upgrade</a> <a class="btn btn-red hud-building-sell">Sell</a> </p> </div> </div>`; this.tierElem = this.componentElem.querySelector(`.hud-building-tier`); this.healthBarElem = this.componentElem.querySelector(`.hud-tooltip-health-bar`); this.statsElem = this.componentElem.querySelector(`.hud-building-stats`); this.actionsElem = this.componentElem.querySelector(`.hud-building-actions`); this.depositElem = this.componentElem.querySelector(`.hud-building-deposit`); this.dualBtnElem = this.componentElem.querySelector(`.hud-building-dual-btn`); this.collectElem = this.componentElem.querySelector(`.hud-building-collect`); this.upgradeElem = this.componentElem.querySelector('.hud-building-upgrade'); this.sellElem = this.componentElem.querySelector('.hud-building-sell'); `Harvester` !== this.buildingId && (this.dualBtnElem.style.display = `none`); this.depositElem.addEventListener(`click`, this.depositIntoBuilding.bind(this)); this.collectElem.addEventListener(`click`, this.collectFromBuilding.bind(this)); this.upgradeElem.addEventListener(`click`, this.upgradeBuilding.bind(this)); this.sellElem.addEventListener(`click`, this.sellBuilding.bind(this)); this.show(); this.update(); } game.ui.components.BuildingOverlay.update = function () { if (this.buildingUid) { const buildingEntity = Game.currentGame.world.getEntityByUid(this.buildingUid); if (!buildingEntity) return void this.stopWatching(); let renderer = Game.currentGame.renderer, buildingUiPosition = renderer.worldToScreen(buildingEntity.getPositionX(), buildingEntity.getPositionY()), buildingTick = buildingEntity.getTargetTick(), buildingsSchema = this.ui.getBuildingSchema(), buildings = this.ui.getBuildings(), buildingSchema = buildingsSchema[this.buildingId], building = buildings[this.buildingUid]; if (!building) return void this.stopWatching(); let buildingHeight = buildingSchema.gridHeight, buildingScale = (buildingSchema.gridWidth, buildingHeight / 2 * 48 * (renderer.getScale() / window.devicePixelRatio)), buildingTier = building.tier, buildingSchemaTier = 1, isBuildingMaxed = false, isBuildingAtMaxTier = false, currentStats = {}, nextTierStats = {}, sameBuildings = 1, buildingStats = { 'health': `Health`, 'damage': `Damage`, 'range': 'Range', 'gps': 'Gold/Sec', 'harvest': `Harvest/Sec`, 'harvestCapacity': `Capacity` }; if (buildingSchema.tiers) { const stashTier = this.getGoldStashTier(); building.tier < buildingSchema.tiers ? (buildingSchemaTier = building.tier + 1, isBuildingMaxed = false) : (buildingSchemaTier = building.tier, isBuildingMaxed = true); isBuildingAtMaxTier = !isBuildingMaxed && (building.tier < stashTier || `GoldStash` === this.buildingId); } for (let buildingStat in buildingStats) { let currentStat = `<small>—</small>`, nextTierStat = '<small>—</small>'; buildingSchema[buildingStat + `Tiers`] && ( currentStat = buildingSchema[buildingStat + `Tiers`][buildingTier - 1].toLocaleString(), isBuildingMaxed || ( nextTierStat = buildingSchema[buildingStat + 'Tiers'][buildingSchemaTier - 1].toLocaleString() ), currentStats[buildingStat] = '<p>' + buildingStats[buildingStat] + `: <strong class="hud-stats-current">` + currentStat + '</strong></p>', nextTierStats[buildingStat] = `<p>` + buildingStats[buildingStat] + ':\x20<strong\x20class=\x22hud-stats-next\x22>' + nextTierStat + `</strong></p>` ); } if (this.shouldUpgradeAll) { sameBuildings = 0; for (let buildingUid in buildings) { // parseInt(buildingUid); tf buildings[buildingUid].type === this.buildingId && buildings[buildingUid].tier === building.tier && sameBuildings++; } } let costString = this.createResourceCostString(buildingSchema, buildingSchemaTier, sameBuildings), refundString = this.createResourceRefundString(this.buildingId, buildingSchema, building.tier), buildingHealth = Math.round(buildingTick.health / buildingTick.maxHealth * 100); buildingTick.partyId !== this.ui.getPlayerPartyId() ? this.actionsElem.style.display = `none` : this.actionsElem.style.display = 'block'; this.tierElem.innerHTML = building.tier.toString(); this.buildingTier = building.tier; this.healthBarElem.style.width = buildingHealth + '%'; if (Object.keys(currentStats).length > 0) { let currentStatValues = '', nextTierStatValues = ''; for (let stat in currentStats) currentStatValues += currentStats[stat]; for (let stat in nextTierStats) nextTierStatValues += nextTierStats[stat]; this.statsElem.innerHTML = ` <div class="hud-stats-current hud-stats-values"> ` + currentStatValues + ` </div> <div class="hud-stats-next hud-stats-values"> ` + nextTierStatValues + ` </div> `; } else this.statsElem.innerHTML = ''; if (`Harvester` === this.buildingId) { let depositAmount = Math.floor(buildingTick.depositMax / 10), isDepositPossible = buildingTick.depositMax - buildingTick.deposit < depositAmount; isDepositPossible ? this.depositElem.classList.add('is-disabled') : this.depositElem.classList.remove(`is-disabled`); this.shouldUpgradeAll ? this.depositElem.innerHTML = 'Refuel\x20All\x20<small>(' + (depositAmount * sameBuildings).toLocaleString() + ` gold)</small>` : this.depositElem.innerHTML = 'Refuel\x20<small>(' + depositAmount.toLocaleString() + ` gold)</small>`; } isBuildingAtMaxTier ? this.upgradeElem.classList.remove(`is-disabled`) : this.upgradeElem.classList.add('is-disabled'); this.shouldUpgradeAll ? ( this.upgradeElem.innerHTML = `Upgrade All <small>(` + costString + ')</small>', this.sellElem.innerHTML = `Sell All <small>(` + refundString + ')</small>' ) : ( this.upgradeElem.innerHTML = `Upgrade <small>(` + costString + `)</small>`, this.sellElem.innerHTML = `Sell <small>(` + refundString + `)</small>` ); `GoldStash` == this.buildingId ? ( this.sellElem.innerHTML = `Sell All Buildings`, this.sellElem.classList.remove(`is-disabled`), this.isSellingAll && this.sellElem.classList.add(`is-disabled`) ) : this.ui.getPlayerPartyCanSell() ? ( this.sellElem.classList.remove(`is-disabled`) ) : ( this.sellElem.classList.add(`is-disabled`), this.sellElem.innerHTML = `Need Permission to Sell` ); this.componentElem.style.left = buildingUiPosition.x - this.componentElem.offsetWidth / 0x2 + 'px'; this.componentElem.style.top = buildingUiPosition.y - buildingScale - this.componentElem.offsetHeight - 0x14 + 'px'; this.rangeIndicator && this.rangeIndicator.setPosition(buildingEntity.getPositionX(), buildingEntity.getPositionY()); } } // @Spammer game.spam = { literallyEveryUnicodeEver: null, randomSpamText: [ // `${garbageGenerator()} BIG RAID ${garbageGenerator()}`, `?verify`, "hi", "ez", "Super Idol的笑容都没你的甜八月正午的阳光都没你耀眼热爱 105 °C的你滴滴清纯的蒸馏水", "Zǎoshang hǎo zhōngguó xiànzài wǒ yǒu BING CHILLING 🥶🍦", "Wǒ hěn xǐhuān BING CHILLING 🥶🍦 Dànshì sùdù yǔ jīqíng 9 bǐ BING CHILLING 🥶🍦", ], spamInterval: null, spamText: '', fetchUnicode: async function() { if (!this.literallyEveryUnicodeEver) { this.literallyEveryUnicodeEver = await fetch('https://raw.githubusercontent.com/bits/UTF-8-Unicode-Test-Documents/master/UTF-8_sequence_unseparated/utf8_sequence_0-0xffff_assigned_printable_unseparated.txt') .then(response => response.text()) .then(data => { return data; }); this.randomSpamText.push(`${garbageGenerator()} BIG RAID ${garbageGenerator()}`); } }, onchange: function({target}) { this.spamText = target.value; }, start: function() { this.spamInterval = setInterval(() => { let text; if (this.spamText !== '') text = `${garbageGenerator()} ${this.spamText} ${garbageGenerator()}`; else text = getRandomItem(this.randomSpamText); game.network.sendRpc({ name: "SendChatMessage", channel: "Local", message: text }); }, 1050); }, stop: function() { clearInterval(this.spamInterval); } } function genUUID() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace( /[018]/g, c => ( c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4 ).toString(16) ); }; function getRandomItem(array) { return array[Math.floor(Math.random() * array.length)]; }; function garbageGenerator(garbageLength = 25) { let garbageCharacters = game.spam.literallyEveryUnicodeEver; let garbage = ""; for (let i = 0; i < garbageLength; i++) garbage += garbageCharacters[Math.floor(Math.random() * garbageCharacters.length)]; return garbage; } function isEven(number) { return number % 2 === 0; }; function isEntityOccupied(x, y) { const cell = game.world.entityGrid.getCellIndexes(x, y, { width: 1, height: 1 }); const entity = game.world.entityGrid.getEntitiesInCell(cell); return Object.keys(entity).length > 0; }; function placeWallBlock(blockWidth, blockHeight, data) { for (let x = -((blockWidth - (isEven(blockWidth) ? 0 : 1)) / 2) * 48; x <= (blockWidth - (isEven(blockWidth) ? 0 : 1)) / 2 * 48; x += 48) { for (let y = -((blockHeight - (isEven(blockHeight) ? 0 : 1)) / 2) * 48; y <= (blockHeight - (isEven(blockHeight) ? 0 : 1)) / 2 * 48; y += 48) { const posX = data.x + x, posY = data.y + y, shouldPlace = !isEntityOccupied(posX, posY); shouldPlace && game.network.sendPacket(9, {name: "MakeBuilding", type: "Wall", x: posX, y: posY, yaw: 0}); }; }; }; function sellAllByType(type) { if (!game.ui.playerPartyCanSell) return; let lastSoldBuilding = null; let allBuildings = [Infinity, ...Object.values(game.ui.buildings).filter(e => e.type == type)]; let sellInterval = () => { if (!game.ui.buildings[lastSoldBuilding?.uid]) allBuildings.shift(); if (window.sellBreak || allBuildings.length == 0) return; const target = allBuildings[0]; if (target !== undefined && !game.ui.buildings[target]?.dead) { lastSoldBuilding = target; Game.currentGame.network.sendRpc({ name: "DeleteBuilding", uid: parseInt(target.uid) }); setTimeout(sellInterval, 50); }; }; sellInterval(); }; function sellAll() { game.ui.components.BuildingOverlay.isSellingAll = true; const sellInterval = () => { if (window.sellBreak) return; if (Object.keys(game.ui.buildings).length > 1 && game.ui.playerPartyCanSell) { Game.currentGame.network.sendRpc({ name: "DeleteBuilding", uid: parseInt(Object.keys(game.ui.buildings)[1]) }); setTimeout(() => { sellInterval(); }, 100); Object.keys(game.ui.buildings).length == 2 && (game.ui.components.BuildingOverlay.isSellingAll = false); } } sellInterval(); } const measureDistance = (obj1, obj2) => { if (!(obj1.x && obj1.y && obj2.x && obj2.y)) return Infinity; let xDif = obj2.x - obj1.x; let yDif = obj2.y - obj1.y; return Math.abs((Math.pow(xDif, 2)) + (Math.pow(yDif, 2))); }; function getByValue(map, searchValue) { for (let [key, value] of map.entries()) { if (equal(value, searchValue)) return key; } } function equal(a, b) { if (a === b) return true; if (a && b && typeof a == 'object' && typeof b == 'object') { if (a.constructor !== b.constructor) return false; var length, i, keys; if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); keys = Object.keys(a); length = keys.length; if (length !== Object.keys(b).length) return false; for (i = length; i-- !== 0;) { if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; } for (i = length; i-- !== 0;) { var key = keys[i]; if (!equal(a[key], b[key])) return false; } return true; } return a!==a && b!==b; }; const addFunctionToElem = ({ id, option, buttonText, colors, onCallback, offCallback }) => { const options = game.options.options; colors ||= 'btn-red?btn-theme'; getId(id).addEventListener('click', e => { let toggleColor = colors.split('?'); if (options[option] === false) { options[option] = true; toggleColor[1] && e.target.classList.remove(toggleColor[1]); e.target.classList.add(toggleColor[0]); buttonText === undefined || (e.target.innerText = `Disable ${buttonText}`); onCallback?.(); } else { options[option] = false; e.target.classList.remove(toggleColor[0]); toggleColor[1] && e.target.classList.add(toggleColor[1]); buttonText === undefined || (e.target.innerText = `Enable ${buttonText}`); offCallback?.(); } }); } function counter(e = 0) { if (e <= -0.99949999999999999e24) { return Math.round(e/-1e23)/-10 + "TT"; } if (e <= -0.99949999999999999e21) { return Math.round(e/-1e20)/-10 + "TB"; } if (e <= -0.99949999999999999e18) { return Math.round(e/-1e17)/-10 + "TM"; } if (e <= -0.99949999999999999e15) { return Math.round(e/-1e14)/-10 + "TK"; } if (e <= -0.99949999999999999e12) { return Math.round(e/-1e11)/-10 + "T"; } if (e <= -0.99949999999999999e9) { return Math.round(e/-1e8)/-10 + "B"; } if (e <= -0.99949999999999999e6) { return Math.round(e/-1e5)/-10 + "M"; } if (e <= -0.99949999999999999e3) { return Math.round(e/-1e2)/-10 + "K"; } if (e <= 0.99949999999999999e3) { return Math.round(e) + ""; } if (e <= 0.99949999999999999e6) { return Math.round(e/1e2)/10 + "K"; } if (e <= 0.99949999999999999e9) { return Math.round(e/1e5)/10 + "M"; } if (e <= 0.99949999999999999e12) { return Math.round(e/1e8)/10 + "B"; } if (e <= 0.99949999999999999e15) { return Math.round(e/1e11)/10 + "T"; } if (e <= 0.99949999999999999e18) { return Math.round(e/1e14)/10 + "TK"; } if (e <= 0.99949999999999999e21) { return Math.round(e/1e17)/10 + "TM"; } if (e <= 0.99949999999999999e24) { return Math.round(e/1e20)/10 + "TB"; } if (e <= 0.99949999999999999e27) { return Math.round(e/1e+23)/10 + "TT"; } if (e >= 0.99949999999999999e27) { return Math.round(e/1e+23)/10 + "TT"; } } const getClock = () => { let date = new Date(), d = date.getDate(), d1 = date.getDay(), h = date.getHours(), m = date.getMinutes(), s = date.getSeconds(), session = "PM"; if (h == 2){ h = 12; }; if (h < 13) { session = "AM" }; if (h > 12){ session = "PM"; h -= 12; }; h = (h < 10) ? "0" + h : h; m = (m < 10) ? "0" + m : m; s = (s < 10) ? "0" + s : s; return `${h}:${m} ${session}`; } function msToTime(s) { // Pad to 2 or 3 digits, default is 2 function pad(n, z) { z = z || 2; return ('00' + n).slice(-z); } var ms = s % 1000; s = (s - ms) / 1000; var secs = s % 60; s = (s - secs) / 60; var mins = s % 60; var hrs = (s - mins) / 60; return pad(hrs) + ':' + pad(mins) + ':' + pad(secs) + '.' + pad(ms, 3); } function ssMode() { const mba = document.querySelectorAll([".hud-bottom-right", ".hud-bottom-left", ".hud-bottom-center", ".hud-center-left", ".hud-center-right", ".hud-chat", ".hud-top-right"]); for (let mb of mba) mb.style.display = (mb.style.display === "none") ? "block" : "none"; document.querySelector(".hud-bottom-right").appendChild(document.querySelector("#hud-shield-bar")); document.querySelector(".hud-bottom-right").appendChild(document.querySelector("#hud-health-bar")); document.querySelector(".hud-bottom-right").insertAdjacentElement("afterbegin", document.querySelector("#hud-party-icons")); document.querySelector(".hud-bottom-left").insertAdjacentElement("afterbegin", document.querySelector("#hud-day-night-ticker")); }; // @TickUpdates game.tickUpdate = { playerTickUpdate: { resourceElem: game.ui.components.Resources, healPlayer: () => { for (let i of ["BuyItem", "EquipItem"]) Game.currentGame.network.sendRpc({name: i, itemName: "HealthPotion", tier: 1}); }, onTick: function(player) { const options = game.options.options; const playerHealth = (player.health / player.maxHealth) * 100; const healThreshold = getId("auto-heal-threshold").valueAsNumber || 25; if (options.autoHeal && playerHealth <= healThreshold) this.healPlayer(); if (!options.frss) return; const resources = ["wood", "stone", "gold"]; for (let rs of resources) { this.resourceElem[`${rs}Elem`].innerHTML = Math.round(player[rs]).toLocaleString(); }; this.resourceElem.tokensElem.innerHTML = Math.round(player.token).toLocaleString(); }, }, petTickUpdate: { buyItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "BuyItem", itemName, tier}), equipItem: (itemName, tier = 1) => Game.currentGame.network.sendRpc({name: "EquipItem", itemName, tier}), petLevelEnum: [8, 16, 24, 32, 48, 64, 96], petTokenEnum: [100, 100, 100, 100, 200, 200, 300, Infinity], onTick: function(pet) { const options = game.options.options; if (options.autoHeal) { if (pet.health <= 0) { this.buyItem("PetRevive"); this.equipItem("PetRevive"); } let petHealth = (pet.health / pet.maxHealth) * 100; const healThreshold = getId("auto-heal-threshold").valueAsNumber || 25; if (petHealth <= healThreshold) { this.buyItem('PetHealthPotion'); this.equipItem("PetHealthPotion"); } }; this.petLevelEnum.indexOf(game.ui.components.MenuShop.shopItems[pet.model].level) > -1 && ( game.ui.playerTick.token >= this.petTokenEnum[pet.tier - 1] && this.buyItem(pet.model, pet.tier + 1) ) }, }, } /* @Handlers + Bindings */ game.network.sendRpc = function(data) { if (data.name === "MakeBuilding" && data.type === "Wall" && game.options.options.wallBlock) { const blockWidth = document.querySelector('#blockX').valueAsNumber; const blockHeight = document.querySelector('#blockY').valueAsNumber; placeWallBlock(blockWidth, blockHeight, data); return; }; this.sendPacket(9, data); }; game.network.addEntityUpdateHandler((e) => { const {entities} = e; const options = game.options.options; if (options.autoBow) { game.network.sendInput({space: 0}); game.network.sendInput({space: 1}); } if (options.autoUpgrade) { for (let uid in game.ui.buildings) { const building = game.ui.buildings[uid]; if (building?.type !== "GoldStash" && building?.tier >= game.rebuilder.goldStash.tier) continue; if (building?.dead || !(uid in game.world.entities)) continue; game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(uid)}); } } if (options.autoUpTowers) { for (let uid in entities) { const currentEntity = entities[uid]; const worldEntity = game.world.entities[uid]; if (currentEntity == true || worldEntity == undefined) continue; if (uid in game.ui.buildings && typeof currentEntity.health == 'number') { const buildingHealth = (currentEntity?.health / worldEntity.targetTick.maxHealth) * 100; const threshold = getId("auto-tower-upgrade-threshold").valueAsNumber; if (buildingHealth <= threshold && worldEntity.targetTick.tier != game.ui.components.BuildingOverlay.getGoldStashTier()) { game.network.sendRpc({name: "UpgradeBuilding", uid: parseInt(uid)}); } }; }; } game.ahrc.onTick(); game.rssOverhead.onTick(entities); game.rebuilder.onTick(entities); game.autoAim.onTick(); }); game.spam.fetchUnicode(); game.network.addRpcHandler("LocalBuilding", game.rebuilder.onLocalBuilding.bind(game.rebuilder)); game.ui._events.playerPetTickUpdate.push(game.tickUpdate.petTickUpdate.onTick.bind(game.tickUpdate.petTickUpdate)); game.ui._events.playerTickUpdate.push(game.tickUpdate.playerTickUpdate.onTick.bind(game.tickUpdate.playerTickUpdate)); (function MapFunctionsToElem() { for (let page in menu) { const [optionsElem, moreElem] = document.querySelectorAll("#" + page + " > div"); for (let option in menu[page]) { const {name, description, more, onCallback, offCallback} = menu[page][option]; const hasMore = !!more; const itemElem = document.createElement("div"); itemElem.innerHTML = ` <h2>${name}</h2> <span>${description}</span> ${game.options.options[option] === undefined ? "" : ` <button id="toggle-${option}" ${game.options.options[option] ? `class="underline-red"` : ""}> ${game.options.options[option] ? "Disable" : "Enable"} </button> `} ${hasMore ? `<a id="more-${option}"></a>` : ""} `; optionsElem.appendChild(itemElem); if (hasMore) { const {html, functions, bind} = more; const moreContainer = document.createElement("div"); moreContainer.innerHTML = html; moreContainer.style.display = "none"; moreElem.appendChild(moreContainer); functions?.(); const toggleElem = getId("more-" + option); toggleElem.onclick = () => { refreshMore(page); bind?.(); moreContainer.style.display = "block"; } } game.options.options[option] === undefined || addFunctionToElem({id: 'toggle-' + option, option, buttonText: '', colors: "underline-red?", onCallback, offCallback}); } } })(); /* @Keybinds */ document.addEventListener('keydown', function(e) { if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") { if (e.key == "/") { game.network.sendRpc({name: "EquipItem", itemName: "PetCARL", tier: game.ui.inventory?.PetCARL?.tier || 1}); } if (e.key === "?") { ssMode(); }; } }); document.addEventListener('keyup', function(e) { if (document.activeElement.tagName.toLowerCase() !== "input" && document.activeElement.tagName.toLowerCase() !== "textarea") { if (e.key == "~") { game.markers.placeMarker({ x: game.ui.playerTick.position.x, y: game.ui.playerTick.position.y, timeout: false, shouldIndicateIndex: true, }); } if (e.key == '-') { game.options.options.getRSS = !game.options.options.getRSS; } if (e.key == "=") { game.world.inWorld && ( game.ui.playerTick.gold > 100 && ( game.ui.inventory.Bow || ( game.network.sendRpc({name: "BuyItem", itemName: "Bow", tier: 1}), game.ui.inventory.Bow = {itemName: 'Bow', tier: 1, stacks: 1} ) ), game.ui.inventory.Bow && ( game.options.options.autoBow = !game.options.options.autoBow, game.options.options.autoBow && game.network.sendRpc({name: "EquipItem", itemName: "Bow", tier: game.ui.inventory.Bow.tier}) ) ) } if (e.key == ",") { getId('toggle-rebuild').click(); } if (e.key == ".") { getId("toggle-autoUpgrade").click(); } if (e.key == ";") { game.ui.getPlayerPetUid() && Game.currentGame.network.sendRpc({name: "DeleteBuilding", uid: game.ui.getPlayerPetUid()}); } if (e.key == "'") { game.ui.getPlayerPetUid() && ( game.network.sendRpc({name: "BuyItem", itemName: "PetRevive", tier: 1}), game.network.sendRpc({name: "EquipItem", itemName: "PetRevive", tier: 1}) ); } if (e.code == 'KeyG') { const wheelDisplay = getClass('interaction-wheel')[0]; wheelDisplay.style.display = (wheelDisplay.style.display === 'block') ? 'none' : 'block'; } if (e.code == 'KeyC' && !e.ctrlKey) { setTimeout(() => { document.querySelector('#joinWithPsk').style.display = 'block'; document.querySelector('#joinWithPsk').focus(); document.querySelector('#joinWithPsk').value = ""; }, 100); } if (e.code == "KeyN") { game.zoom.zoomIn(); } if (e.code == "KeyM") { game.zoom.zoomOut(); } if (e.key == "Escape") { getClass('interaction-wheel')[0].style.display = 'none'; } if (e.key == "!") { getId("toggle-wallBlock").click(); } } }); document.querySelector('#joinWithPsk').addEventListener('keyup', (e) => { if (e.key == "Enter" || e.key == "Escape") { e.target.style.display = 'none'; (e.key == "Enter") && game.network.sendRpc({name: "JoinPartyByShareKey", partyShareKey: e.target.value}); } })