From 8e2049e6ff643b2401fc51a7fb1af465cafee3e2 Mon Sep 17 00:00:00 2001 From: Gaurav Arya Date: Thu, 30 Dec 2021 13:29:06 -0500 Subject: [PATCH 1/2] Add blue miner and portable building images --- .../static/img/robots/blue_lab_portable.png | Bin 0 -> 612 bytes .../src/static/img/robots/blue_miner.png | Bin 3103 -> 2220 bytes .../img/robots/blue_watchtower_portable.png | Bin 0 -> 474 bytes .../static/img/robots/red_lab_portable.png | Bin 0 -> 584 bytes .../img/robots/red_watchtower_portable.png | Bin 0 -> 476 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/visualizer/src/static/img/robots/blue_lab_portable.png create mode 100644 client/visualizer/src/static/img/robots/blue_watchtower_portable.png create mode 100644 client/visualizer/src/static/img/robots/red_lab_portable.png create mode 100644 client/visualizer/src/static/img/robots/red_watchtower_portable.png diff --git a/client/visualizer/src/static/img/robots/blue_lab_portable.png b/client/visualizer/src/static/img/robots/blue_lab_portable.png new file mode 100644 index 0000000000000000000000000000000000000000..f0d5ee8d713b81a94b0b2e1cbc2c2473029f2e87 GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBsPB=d zi(^Oz>)nHndD5v83>Usz#wQ+S^*GA3@ZOvF^R~NYe~sa7Y`GQJz^k#%eu>mcN$Z)N zGmn^lj*IHtB9y6m=`{y?;{my+U6-B;MJHFEZfU)=hxc2b+#GIwalTU*)$d5}cDB?o zzO=`_;Qb40n;-8_?fibs?1tp+1vbjQ+BpI1vil9fZY;1-JgdEZv5oRs?c_wAfVlhb zZ#+=1F;qUwo&5BUb`gu7^s*>b<%@IVqU^w9bw}B!G+P^A>Y2atzRXwW%G|#Jet#})y|LS2 z);eQ%({gBY#fN5Uq7s#KQnzP}1%a{L~zW0E`qxV(R4wqewvE0jlEws6|)j;)b zL!E~A(y1QW6T_6&x~GF2{M#$w}QGLQ{c)oj}t{b!`-TS~OoCP3kTH`cZ7PN|~6)>DJ|~ r8+pHJq#p`;`F6_2x#m+K_SG}IY^aK1EpD6+Oa=^|u6{1-oD!M};470Ukr000SaNLh0L04^f{ z04^f|c%?sf0006HlM(??12rx*lVt&e5nOl>pMi79zX8`Z6u8LLp3Hgb6IzKXRc}!9{vaY%pZ@^5aTbFfJ5b)scNmZz_ zK$w~CZ~8Jl0Pz1&dIpq(Xo(0*_xzbUG~K>Me`!7K|7T&)(=}oUg7JFyYdf8|YRjk_ zTTN@H8%4tz5Gp{he>-u@!FS!Nwc;ve-_l>Pj-Clek7&_3(^)|b&a@weCic!AUUB1A zAn5A0iG~4>pDhA`pf>BRHc{BRLieLC*;0<0mHVSq!&To0Xc6N-ZLqFYQJ(CIis0DGef)3GZjn z)QzXImZ{t#Z`!LqV!ZHQcv^L7Ah8SvcN)B~7%b;B2;x;7Y(e+$I^BMhg%GE8w#n~i4JQHm2` z_U`gCKTzwQnDVRJ2E#SINkEbJg*G45fNLa%e3ZWcUbzb zf5`R98O#rXv{Z+dqrZ*>W&M%BZUs#U_m();F1?dok*T{ukKOE`x47IkrTw)a=s|;4 z{F0$aOh{n!?7}kJol;cW-3mjBYYg*FlC`I~1_bZXv(fmG=c!ot{vM)O<8!3Q;qpZD zQX@xt5-7jb)h%%B++Q$6R;(U0k-bERf8B}8R)Kh*)kBLyR~-CQZ$0cwESbEtm&K)K zsg1RGIhKu4J_M41AzR`lCB+s}|F}^Y?xgNhaud(x7Y1>`HLw1hhd&?WSf;e#;^d)2 z0onYh z^Q91ibq3N_jp%hWE%c#A0=vZ!f4_l|YVk`fk=W+cZ;bYz(4cpEKWYDdmST?Im>Wyx z7TM`tPSJ}~i+B*+^Y^dhHBI_35)*zfj2S|z*s4=(y3m}vry$0FY3j)^y5uR{hY?L^ zQ)KgzBfh%FSuW(X(c3Kj#nC=PaoOQLjO>Qi;!Z_M@#-|q87T|ot(#usP58MkE4sLo z!yj&Vk9}&z91&mtc&9Leo@xKtI_OF)#J?9F V9$Dyz)6M_@002ovPDHLkV1hXx69@nR delta 2476 zcmZ{mc{tQ-AI5*P*t2gZOO`A#mLXag##WYQF!rr7hG8_xOe2H%F=We{oGdvA;UGs@ zv*m=W5tTL4W~rH8J0Y*mbq>s;^q{P8@W>;8W4`~LT-6wLoAO#y`a8e@$CpeB`P z7taO&fGokn4hsOGN&pZU0|4I+q{syT2toqDk|zM@WdVSA;N8bK)WIOl$HkI}#R94a z%n7hV*a6r9K>+B%CG;ml4p;*Ck$gaa6GZYqd;xL{fQkHNh$8{;KbMH<*A3xiRQ}TR zHgPCSEPc!tc0vQ0p$aJ$QBz9;sVSeqfa+y9K+zeq zkOk-$c}p1U*|4-G}UAM!M`1aP@~r7m3pRpM!rI zO|OuzQ0)Wp1fL&0e^?GAgTJ(YuK&^F`u}?V9Awl$PlNOQxN!jB7_&4pcJO2CawCx) z97Vpfa!X3oYuSt;mvu%)%H;*ryr#L|i3L-NMYZC25-AB1xO**jFW8{Ur7lq`*}<7Uclzz3%)Z0Eh;CoTbl2NJ>Ojj_*%GkNWZ2Zv36WBHGm14<4ap)YrXWTf|I5D1SDmyV;i&7ic z<&hEJBX=t}<%`{XGP1RFJjX8?UA7QaxKJW%&9Lnf@IVi~F%Ol{*I=YnY&8q;_tv&W z(ZOFf0GyESywa1J*t#_TZdHa@FPF6PIwj|x_9&L_5N=k}EZieNa5qC5pSuM#YTPSz?nL*JcM@LbEgo zg=7iGNZzK=K+8+g0e%x)H0gfD_?tMlt8F(H_Y^3FtbEZ{d3vSfMeE06A2V28L{Qbg z%Azq@qMf^amttBH9{*}C;&|$ivK@a!MPT9P6|0m8N=sfH6+Fsb)K>U64 z+gj|ehnGW87gCQqj1hsg|X*09buR`w$c2 zAGmJ&yZUAYrfC$-!H0N z8+@O9%rX}^cMQo=dyVO383vzly>{OGViSBONBDXdQI^K49O%zRsFyfc)i?QJQXu?N ze3`5`(Xc4`X6VAS4{F>1#M^x#bGkm++{sQ?W5OQ#fqJ#WQrwMlcJZy3DeSWy&z~_K zuRaH!(6_03+?)!%@r&vqpUswypSh23h!h&9DBab>O#C*R46vXSx38<}iE zCL!kDXy3E3q8i-}ao4_+wm9W|sw#C6iE@0I!sIWUHCBxb@+- z`1zJt(j5MUAV+@rKu16)6Qs$cB|u!iNcQs7otdt%!3AcGb`@I4kd8uHpryEh+-C9K zQU7a;-fNE!$!!iM;&vO3@xLl5Jlvq&sWHDx37=G06ZxG3TNzXO8&vfDZq^E2J(JL< z=@3Bth?K?}=wLu_Yiw&~B2#fP=>~1d_t>!n=F4!&p$c5MqM?2;VO(BqTA%NH$Bv4r zVy+Y4D=Xh+_u##t#JQ~-(+177ug|r1d|@GJZ?Yejg^19C z;4U~g2AfGU#qFHjdwOb3U~^ zVwnxP9+V}2R;Wzu$7g-Ui ziBpGaheFyJ`X7$CRqUuG9I0bv42;xH?7k7Iej6AX>s%-Z4@W=*62~YidE3cBJ(s=< z^X-et@`8woJrp?TkJ3vkYVHoy&$E76qh8vWEj|u0fA ztBF{Cl(}qbTX$9HNni72K~V!}2Zw+^!e%!-w>xgUXU*sI>%7%m#h@y|@<+tCLT~TS zQU{zTo5Q$|_ERldMOtNiE0O&3-{A=<=e4&A%@@OdFe{0eUzfqjJ-{LK6Fs7=Az=&zsW zR6x$5d~4Z9?M2Vb?}lx4$ZUJh=1nOp-QRh?Pi*W`ZUrYSlCX?Np=u*aFw8s5EDVlj z>GK8zMVKYJ#Z33dtRSwtG@@0{C$fh{R%()O%$40w;zd0%nLe_FR&d<%ar}){s_)IL zZ{Eft`)~zqx-j>-z!f<9wBoLjgE-f7utn#T8>6hpSy%lw zoxMDKw2H-xd1VgvJF^VW^*f3C$abP(^mPBU*Zi3Q622^)XEDwhKltT&d=35*A9uTH zpZB*xbn8z=ZOW`Mm;IYVhH<#WYQj!(1{Xu`EqHX5tm;m?5OVMr0xZv1n>~P;cryMC D4#`)8 diff --git a/client/visualizer/src/static/img/robots/blue_watchtower_portable.png b/client/visualizer/src/static/img/robots/blue_watchtower_portable.png new file mode 100644 index 0000000000000000000000000000000000000000..03388193edc2873dc7c00541eef02ddbb1444b08 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBs4v3P z#W5s<_3lB#yxR^Ut`~o=y}rzQ?wUT+>qcMK=&ifEwC8|0BTvGSd5VeA%ANmZCboDu zsVHvawD>H+WFWif{2T6DXZAg?-K?J>kb8fJ#?>!pf;TJ;xoqt3=)ZDV`n)E&i{EB9 z3&tngosXFq!J1&VAmnr8(plNU+QkKrD&{q`njiT%gKcBtye9S(DVO*STnU<2?;N&a z6<1G4Y`&5HEbh|KPl!v!E9AIx#aP9$5dWTBv(~M}e)PasHhd5)arv zoXPEEoL8CJ!C*W?;&=?pc11Rgt9NFB96L$CvqQy2NQo2T_HV503g2cjBLr`hKl;Zq z=cdB8nf1>!cPzGF)5Lf2iSUt~A)h^-Y4Wh}F48==be4PYs+r3T1oi+;ll?3r)0t7t zbmo84)R)`}4GF1nk_PeOCLLy<=iN*{(32|VB2>?4xW#`{!c@5_z`$qlboFyt=akR{ E0Q0T0asU7T literal 0 HcmV?d00001 diff --git a/client/visualizer/src/static/img/robots/red_lab_portable.png b/client/visualizer/src/static/img/robots/red_lab_portable.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1d0afafb43fd2e09327adfd0cfcf1c79153cf1 GIT binary patch literal 584 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBsPCAk zi(^Oz>)nHldD5W*3>VDLiM(@Ap0MM^3weg% zX?ONe5uhV5Wtg8w%_rzIbxW|9Ec}4b?WAub+fBVk&?K|B3 ze_iY@^R0&`uav#TeQD1zzPHJ51(!)#Z%JR0`nGI~_>$CIEg#lfw}10m|LIsSwj?!i zRqU@8_vuWzk-J6u_8p&}wxlvXmMgftVvFC5@6%Z`@9|HwRjf${I^;Ju`&-$iQ)h8} zyT+-#^z~NZM!CaMfmiif7h7{*YMTEtUiPcRy{P_&F(F&Em$2^dc^Lh|a88$2@uj8} zMg97GRXp;Ft74RO!Gh1Lc(Prl7TdN32d4V%3Ib`0Tzq^(SQWEv8~>)m_lz(7KYfq; zlG~DA4|6S`uDcB@ie9OIk??b!YWb4wi^MfA>4|1axh|kEdg*pI{O94nt0r_G?spj{~1QBNS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBs4vRX z#W5s<_3lCMJYh!>h67a}Z*NRx6_VL{^?HiCNZC%tgZ&lnX5+`Kh>54)9SGk{rjfdEt6UQ z=I6tTO!a_!3#-c4yt=z`>D;2nm)`C?d~IGy^{JK;hb_;zrgCP+-QdhwT|Ql4ZRNIu z*BCP+ckWrsnkkUUdU2NO)!o5fuQ`RgIJWuetbJf?FYn8Jit7@W+|PGsE^+O9c&~D) z=$-07mw>Qo*MjG@e)iB_ac^$4lnW+|63cUl3d?gq$V6=`tn5^0Uvl`A{l!__zjD>j zcnEj-ehAsSTkT?$qK}7g)ACn$x30YBn%%lVomc5>$F)0?Oy2T6-MS(887oub@;w?; q`niQKZTS=y8K&`COZbw)Kc)x!{d2qCbo~PcKZB>MpUXO@geCxu=e-92 literal 0 HcmV?d00001 From 4d6880a6fac0cdbc60e326dddccd7bc3b36e9bcd Mon Sep 17 00:00:00 2001 From: Aidan Blum Levine Date: Thu, 30 Dec 2021 13:44:07 -0500 Subject: [PATCH 2/2] Lead and gold icons and map display changes --- client/package-lock.json | 10 +- client/playback/package-lock.json | 1110 +---------------- client/visualizer/src/constants.ts | 124 +- client/visualizer/src/gamearea/renderer.ts | 465 +++---- client/visualizer/src/imageloader.ts | 315 ++--- .../src/static/img/resources/gold.png | Bin 0 -> 547 bytes .../src/static/img/resources/lead.png | Bin 0 -> 563 bytes .../src/static/img/tiles/terrain2.png | Bin 0 -> 3016 bytes .../src/static/img/tiles/terrain3.png | Bin 0 -> 2473 bytes 9 files changed, 497 insertions(+), 1527 deletions(-) create mode 100644 client/visualizer/src/static/img/resources/gold.png create mode 100644 client/visualizer/src/static/img/resources/lead.png create mode 100644 client/visualizer/src/static/img/tiles/terrain2.png create mode 100644 client/visualizer/src/static/img/tiles/terrain3.png diff --git a/client/package-lock.json b/client/package-lock.json index 1068690b..9c5f0fde 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,13 +1,5 @@ { "name": "battlecode-client", "version": "2022.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "battlecode-client", - "version": "2022.0.0", - "license": "GPL-3.0" - } - } + "lockfileVersion": 1 } diff --git a/client/playback/package-lock.json b/client/playback/package-lock.json index a1afa9bb..384eed44 100644 --- a/client/playback/package-lock.json +++ b/client/playback/package-lock.json @@ -1,1097 +1,7 @@ { "name": "battlecode-playback", - "lockfileVersion": 2, "requires": true, - "packages": { - "": { - "name": "battlecode-playback", - "license": "GPL-3.0", - "dependencies": { - "battlecode-schema": "file:../../schema", - "core-js": "^3.3.6", - "deepcopy": "^2.0.0", - "pako": "^1.0.10", - "victor": "^1.1.0" - }, - "devDependencies": { - "@types/blue-tape": "^0.1.33", - "@types/core-js": "^2.5.2", - "@types/node": "^12.12.5", - "@types/pako": "^1.0.1", - "@types/victor": "^1.1.0", - "blue-tape": "^1.0.0", - "npm-force-resolutions": "0.0.3", - "stream": "0.0.2", - "tap-dot": "^2.0.0", - "ts-node": "^8.4.1", - "tslint": "^5.20.0", - "typescript": "^3.6.4" - } - }, - "../../schema": { - "name": "battlecode-schema", - "version": "2022.0.0", - "license": "GPL-3.0", - "dependencies": { - "@types/flatbuffers": "^1.9.1", - "flatbuffers": "^1.11.0" - } - }, - "../../schema/node_modules/@types/flatbuffers": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", - "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" - }, - "../../schema/node_modules/flatbuffers": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", - "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" - }, - "node_modules/@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.0.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "dependencies": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@types/blue-tape": { - "version": "0.1.33", - "resolved": "https://registry.npmjs.org/@types/blue-tape/-/blue-tape-0.1.33.tgz", - "integrity": "sha512-l5cQcLM3aPh55bBQ4geWQ8hZ4Ew+s4RvyhMaBpgW3aJ2HUfRgwd8ENKrk/utC4Hz1dJAiehyIa4vN6emxBMaog==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tape": "*" - } - }, - "node_modules/@types/core-js": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-2.5.2.tgz", - "integrity": "sha512-+NPqjXgyA02xTHKJDeDca9u8Zr42ts6jhdND4C3PrPeQ35RJa0dmfAedXW7a9K4N1QcBbuWI1nSfGK4r1eVFCQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "12.12.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.5.tgz", - "integrity": "sha512-KEjODidV4XYUlJBF3XdjSH5FWoMCtO0utnhtdLf1AgeuZLOrRbvmU/gaRCVg7ZaQDjVf3l84egiY0mRNe5xE4A==", - "dev": true - }, - "node_modules/@types/pako": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.1.tgz", - "integrity": "sha512-GdZbRSJ3Cv5fiwT6I0SQ3ckeN2PWNqxd26W9Z2fCK1tGrrasGy4puvNFtnddqH9UJFMQYXxEuuB7B8UK+LLwSg==", - "dev": true - }, - "node_modules/@types/tape": { - "version": "4.2.33", - "resolved": "https://registry.npmjs.org/@types/tape/-/tape-4.2.33.tgz", - "integrity": "sha512-ltfyuY5BIkYlGuQfwqzTDT8f0q8Z5DGppvUnWGs39oqDmMd6/UWhNpX3ZMh/VYvfxs3rFGHMrLC/eGRdLiDGuw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/victor": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/victor/-/victor-1.1.0.tgz", - "integrity": "sha512-37o+SnbGRoWqb2+6GQ3NoFX8Ff5zCvm0XsXFulNvO89t2zKluqb4twVORheAnmQ+iEd0rKzAcBGC2//3XBoU1A==", - "dev": true - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", - "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/battlecode-schema": { - "resolved": "../../schema", - "link": true - }, - "node_modules/blue-tape": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/blue-tape/-/blue-tape-1.0.0.tgz", - "integrity": "sha1-dYHQTAc5XJXEJrLtbR7bRUp2uSs=", - "dev": true, - "dependencies": { - "tape": ">=2.0.0 <5.0.0" - }, - "bin": { - "blue-tape": "bin/blue-tape.js" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/core-js": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.6.tgz", - "integrity": "sha512-u4oM8SHwmDuh5mWZdDg9UwNVq5s1uqq6ZDLLIs07VY+VJU91i3h4f3K/pgFvtUQPGdeStrZ+odKyfyt4EnKHfA==", - "hasInstallScript": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true - }, - "node_modules/deepcopy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.0.0.tgz", - "integrity": "sha512-d5ZK7pJw7F3k6M5vqDjGiiUS9xliIyWkdzBjnPhnSeRGjkYOGZMCFkdKVwV/WiHOe0NwzB8q+iDo7afvSf0arA==", - "dependencies": { - "type-detect": "^4.0.8" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/emitter-component": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz", - "integrity": "sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", - "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "dependencies": { - "has": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-format": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-format/-/json-format-1.0.1.tgz", - "integrity": "sha1-FD9n5irxKda//tKIpGJl6iPQ3ww=", - "dev": true - }, - "node_modules/make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/npm-force-resolutions": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/npm-force-resolutions/-/npm-force-resolutions-0.0.3.tgz", - "integrity": "sha512-xbIPAGzD3nrJHDLtnRFt/O83teTA8ju5pWTf8W6OKL4D0XD9EjdRNJhzg4bSXWuucE+l1HGdTpOJR/l1Mi1Ycg==", - "dev": true, - "dependencies": { - "json-format": "^1.0.1", - "source-map-support": "^0.5.5" - }, - "bin": { - "npm-force-resolutions": "index.js" - } - }, - "node_modules/object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/re-emitter": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/re-emitter/-/re-emitter-1.1.4.tgz", - "integrity": "sha512-C0SIXdXDSus2yqqvV7qifnb4NoWP7mEBXJq3axci301mXHCZb8Djwm4hrEZo4UeXRaEnfjH98uQ8EBppk2oNWA==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dev": true, - "dependencies": { - "through": "~2.3.4" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stream": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz", - "integrity": "sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=", - "dev": true, - "dependencies": { - "emitter-component": "^1.1.1" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", - "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.0", - "function-bind": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap-dot": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tap-dot/-/tap-dot-2.0.0.tgz", - "integrity": "sha512-7N1yPcRDgdfHCUbG6lZ0hXo53NyXhKIjJNhqKBixl9HVEG4QasG16Nlvr8wRnqr2ZRYVWmbmxwF3NOBbTLtQLQ==", - "dev": true, - "dependencies": { - "chalk": "^1.1.1", - "tap-out": "^1.3.2", - "through2": "^2.0.0" - }, - "bin": { - "tap-dot": "bin/dot" - } - }, - "node_modules/tap-out": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tap-out/-/tap-out-1.4.2.tgz", - "integrity": "sha1-yQfsG/lAURHQiCY+kvVgi4jLs3o=", - "dev": true, - "dependencies": { - "re-emitter": "^1.0.0", - "readable-stream": "^2.0.0", - "split": "^1.0.0", - "trim": "0.0.1" - }, - "bin": { - "tap-out": "bin/cmd.js" - } - }, - "node_modules/tape": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.11.0.tgz", - "integrity": "sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA==", - "dev": true, - "dependencies": { - "deep-equal": "~1.0.1", - "defined": "~1.0.0", - "for-each": "~0.3.3", - "function-bind": "~1.1.1", - "glob": "~7.1.4", - "has": "~1.0.3", - "inherits": "~2.0.4", - "minimist": "~1.2.0", - "object-inspect": "~1.6.0", - "resolve": "~1.11.1", - "resumer": "~0.0.0", - "string.prototype.trim": "~1.1.2", - "through": "~2.3.8" - }, - "bin": { - "tape": "bin/tape" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, - "node_modules/ts-node": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", - "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" - }, - "bin": { - "ts-node": "dist/bin.js" - }, - "engines": { - "node": ">=4.2.0" - }, - "peerDependencies": { - "typescript": ">=2.0" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "node_modules/tslint": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", - "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" - } - }, - "node_modules/tslint/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", - "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/victor": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/victor/-/victor-1.1.0.tgz", - "integrity": "sha1-3jzHexVYmxsMeyLD2tKXA0qwAro=" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { "version": "7.5.5", @@ -1733,15 +643,6 @@ "emitter-component": "^1.1.1" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "string.prototype.trim": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", @@ -1773,6 +674,15 @@ "function-bind": "^1.1.1" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", diff --git a/client/visualizer/src/constants.ts b/client/visualizer/src/constants.ts index 40de2e26..55c70706 100644 --- a/client/visualizer/src/constants.ts +++ b/client/visualizer/src/constants.ts @@ -1,21 +1,29 @@ -import { schema } from 'battlecode-playback'; -import { Symmetry } from './mapeditor/index'; +import { schema } from 'battlecode-playback' +import { Symmetry } from './mapeditor/index' // Body types -export const ARCHON = schema.BodyType.ARCHON; -export const BUILDER = schema.BodyType.BUILDER; -export const LABORATORY = schema.BodyType.LABORATORY; -export const MINER = schema.BodyType.MINER; -export const SAGE = schema.BodyType.SAGE; -export const SOLDIER = schema.BodyType.SOLDIER; -export const WATCHTOWER = schema.BodyType.WATCHTOWER; - -export const bodyTypeList: number[] = [ARCHON, BUILDER, LABORATORY, MINER, SAGE, SOLDIER, WATCHTOWER]; -export const initialBodyTypeList: number[] = [ARCHON]; - -export const bodyTypePriority: number[] = []; // for guns, drones, etc. that should be drawn over other robots - -export const TILE_COLORS: Array[] = [[119, 228, 88], [144, 230, 83], [166, 231, 79], [187, 232, 76], [206, 233, 76], [231, 207, 66], [245, 182, 72], [249, 158, 86], [219, 115, 109], [163, 90, 118], [99, 73, 103], [51, 52, 65]]; +export const ARCHON = schema.BodyType.ARCHON +export const BUILDER = schema.BodyType.BUILDER +export const LABORATORY = schema.BodyType.LABORATORY +export const MINER = schema.BodyType.MINER +export const SAGE = schema.BodyType.SAGE +export const SOLDIER = schema.BodyType.SOLDIER +export const WATCHTOWER = schema.BodyType.WATCHTOWER + +export const bodyTypeList: number[] = [ARCHON, BUILDER, LABORATORY, MINER, SAGE, SOLDIER, WATCHTOWER] +export const initialBodyTypeList: number[] = [ARCHON] + +export const bodyTypePriority: number[] = [] // for guns, drones, etc. that should be drawn over other robots + +export const TILE_COLORS: Array[] = [ + [168, 137, 97], + [147, 117, 77], + [88, 129, 87], + [58, 90, 64], + [52, 78, 65], + [11, 32, 39], + [8, 20, 20] +] // flashy colors // [0, 147, 83], // turquoise // [29, 201, 2], // green @@ -26,45 +34,45 @@ export const TILE_COLORS: Array[] = [[119, 228, 88], [144, 230, 83], [16 // Given passability, get index of tile to use. export const getLevel = (x: number): number => { - const nLev = TILE_COLORS.length; - const floatLevel = ((1 - x) - 0.1) / 0.9 * nLev; + const nLev = TILE_COLORS.length + const floatLevel = ((1 - x) - 0.1) / 0.9 * nLev const level = Math.floor(floatLevel) - return Math.min(nLev - 1, Math.max(0, level)); + return Math.min(nLev - 1, Math.max(0, level)) } export const passiveInfluenceRate = (round: number): number => { //return Math.floor((1/50 + 0.03 * Math.exp(-0.001 * x)) * x); this one's for slanderers - return Math.ceil(0.2 * Math.sqrt(round)); + return Math.ceil(0.2 * Math.sqrt(round)) } export const buffFactor = (numBuffs: number): number => { - return 1 + 0.001 * numBuffs; + return 1 + 0.001 * numBuffs } -export const ACTION_RADIUS_COLOR = "#46ff00"; -export const VISION_RADIUS_COLOR = "#0000ff"; +export const ACTION_RADIUS_COLOR = "#46ff00" +export const VISION_RADIUS_COLOR = "#0000ff" // Expected bot image size -export const IMAGE_SIZE = 50; +export const IMAGE_SIZE = 50 // Game canvas rendering sizes -export const INDICATOR_DOT_SIZE = .3; -export const INDICATOR_LINE_WIDTH = .3; +export const INDICATOR_DOT_SIZE = .3 +export const INDICATOR_LINE_WIDTH = .3 export const SIGHT_RADIUS_LINE_WIDTH = .15 // Game canvas rendering parameters -export const EFFECT_STEP = 200; //time change between effect animations +export const EFFECT_STEP = 200 //time change between effect animations // Map editor canvas parameters -export const DELTA = .0001; -export const MIN_DIMENSION = 15; -export const MAX_DIMENSION = 100; +export const DELTA = .0001 +export const MIN_DIMENSION = 15 +export const MAX_DIMENSION = 100 // Initial influence of enlightenment center, for map editor -export const INITIAL_INFLUENCE = 150; +export const INITIAL_INFLUENCE = 150 // Server settings -export const NUMBER_OF_TEAMS = 2; +export const NUMBER_OF_TEAMS = 2 // export const VICTORY_POINT_THRESH = 1000; // Other constants @@ -84,12 +92,12 @@ export enum MapType { // Map types to filter in runner export const mapTypes: MapType[] = [MapType.DEFAULT, - MapType.SPRINT_1, - MapType.SPRINT_2, - MapType.QUALIFYING, - MapType.HS_NEWBIE, - MapType.FINAL, - MapType.CUSTOM]; +MapType.SPRINT_1, +MapType.SPRINT_2, +MapType.QUALIFYING, +MapType.HS_NEWBIE, +MapType.FINAL, +MapType.CUSTOM] export const SERVER_MAPS: Map = new Map([ ["maptestsmall", MapType.DEFAULT], @@ -168,57 +176,57 @@ export const SERVER_MAPS: Map = new Map([ ["Stonks", MapType.FINAL], ["TheClientMapEditorIsSuperiorToGoogleSheetsEom", MapType.FINAL], ["TheSnackThatSmilesBack", MapType.FINAL] -]); +]) export function bodyTypeToString(bodyType: schema.BodyType) { switch (bodyType) { case ARCHON: - return "archon"; + return "archon" case WATCHTOWER: - return "watchtower"; + return "watchtower" case BUILDER: - return "builder"; + return "builder" case MINER: - return "miner"; + return "miner" case SAGE: - return "sage"; + return "sage" case SOLDIER: - return "soldier"; + return "soldier" case LABORATORY: - return "laboratory"; - default: throw new Error("invalid body type"); + return "laboratory" + default: throw new Error("invalid body type") } } export function symmetryToString(symmetry: Symmetry) { switch (symmetry) { - case Symmetry.ROTATIONAL: return "Rotational"; - case Symmetry.HORIZONTAL: return "Horizontal"; - case Symmetry.VERTICAL: return "Vertical"; - default: throw new Error("invalid symmetry"); + case Symmetry.ROTATIONAL: return "Rotational" + case Symmetry.HORIZONTAL: return "Horizontal" + case Symmetry.VERTICAL: return "Vertical" + default: throw new Error("invalid symmetry") } } export function abilityToEffectString(effect: number): string | null { switch (effect) { case 1: - return "empower"; + return "empower" case 2: - return "expose"; + return "expose" case 3: - return "embezzle"; + return "embezzle" case 4: - return "camouflage_red"; + return "camouflage_red" case 5: - return "camouflage_blue"; + return "camouflage_blue" default: - return null; + return null } } // TODO: fix radius (is this vision that can be toggled in sidebar?) export function radiusFromBodyType(bodyType: schema.BodyType) { - return -1; + return -1 // switch(bodyType) { // case MINER: // case LANDSCAPER: diff --git a/client/visualizer/src/gamearea/renderer.ts b/client/visualizer/src/gamearea/renderer.ts index 29fef393..be9f8665 100644 --- a/client/visualizer/src/gamearea/renderer.ts +++ b/client/visualizer/src/gamearea/renderer.ts @@ -1,11 +1,11 @@ -import * as config from '../config'; -import * as cst from '../constants'; -import NextStep from './nextstep'; +import * as config from '../config' +import * as cst from '../constants' +import NextStep from './nextstep' -import {GameWorld, Metadata, schema, Game} from 'battlecode-playback'; -import {AllImages} from '../imageloader'; -import Victor = require('victor'); -import { constants } from 'buffer'; +import { GameWorld, Metadata, schema, Game } from 'battlecode-playback' +import { AllImages } from '../imageloader' +import Victor = require('victor') +import { constants } from 'buffer' /** * Renders the world. @@ -14,25 +14,25 @@ import { constants } from 'buffer'; */ export default class Renderer { - readonly ctx: CanvasRenderingContext2D; + readonly ctx: CanvasRenderingContext2D // For rendering robot information on click - private lastSelectedID: number; + private lastSelectedID: number // position of mouse cursor hovering - private hoverPos: {x: number, y: number} | null = null; + private hoverPos: { x: number, y: number } | null = null; constructor(readonly canvas: HTMLCanvasElement, readonly imgs: AllImages, private conf: config.Config, readonly metadata: Metadata, readonly onRobotSelected: (id: number) => void, readonly onMouseover: (x: number, y: number, xrel: number, yrel: number, passability: number) => void) { - let ctx = canvas.getContext("2d"); + let ctx = canvas.getContext("2d") if (ctx === null) { - throw new Error("Couldn't load canvas2d context"); + throw new Error("Couldn't load canvas2d context") } else { - this.ctx = ctx; + this.ctx = ctx } - this.ctx['imageSmoothingEnabled'] = false; + this.ctx['imageSmoothingEnabled'] = false } @@ -48,22 +48,24 @@ export default class Renderer { // setup correct rendering const viewWidth = viewMax.x - viewMin.x const viewHeight = viewMax.y - viewMin.y - const scale = this.canvas.width / (!this.conf.doingRotate ? viewWidth : viewHeight); + const scale = this.canvas.width / (!this.conf.doingRotate ? viewWidth : viewHeight) - this.ctx.save(); - this.ctx.scale(scale, scale); - if (!this.conf.doingRotate) this.ctx.translate(-viewMin.x, -viewMin.y); - else this.ctx.translate(-viewMin.y, -viewMin.x); + this.ctx.save() + this.ctx.scale(scale, scale) + if (!this.conf.doingRotate) this.ctx.translate(-viewMin.x, -viewMin.y) + else this.ctx.translate(-viewMin.y, -viewMin.x) - this.renderBackground(world); - this.renderResources(world); + this.renderBackground(world) + this.renderResources(world) - this.renderBodies(world, curTime, nextStep, lerpAmount); - this.renderIndicatorDotsLines(world); - this.setMouseoverEvent(world); + this.renderBodies(world, curTime, nextStep, lerpAmount) + this.renderHoverBox(world) + + this.renderIndicatorDotsLines(world) + this.setMouseoverEvent(world) // restore default rendering - this.ctx.restore(); + this.ctx.restore() } /** @@ -74,123 +76,154 @@ export default class Renderer { } private renderBackground(world: GameWorld) { - this.ctx.save(); - this.ctx.fillStyle = "white"; - this.ctx.globalAlpha = 1; + this.ctx.save() + this.ctx.fillStyle = "white" + this.ctx.globalAlpha = 1 - let minX = world.minCorner.x; - let minY = world.minCorner.y; - let width = world.maxCorner.x - world.minCorner.x; - let height = world.maxCorner.y - world.minCorner.y; + let minX = world.minCorner.x + let minY = world.minCorner.y + let width = world.maxCorner.x - world.minCorner.x + let height = world.maxCorner.y - world.minCorner.y - const scale = 20; + const scale = 20 - this.ctx.scale(1/scale, 1/scale); + this.ctx.scale(1 / scale, 1 / scale) // scale the background pattern - if (!this.conf.doingRotate) this.ctx.fillRect(minX*scale, minY*scale, width*scale, height*scale); - else this.ctx.fillRect(minY*scale, minX*scale, height*scale, width*scale); + if (!this.conf.doingRotate) this.ctx.fillRect(minX * scale, minY * scale, width * scale, height * scale) + else this.ctx.fillRect(minY * scale, minX * scale, height * scale, width * scale) - const map = world.mapStats; + const map = world.mapStats - for (let i = 0; i < width; i++) for (let j = 0; j < height; j++){ - let idxVal = map.getIdx(i,j); - let plotJ = height-j-1; + for (let i = 0; i < width; i++) for (let j = 0; j < height; j++) { + let idxVal = map.getIdx(i, j) + let plotJ = height - j - 1 - const cx = (minX+i)*scale, cy = (minY+plotJ)*scale; + const cx = (minX + i) * scale, cy = (minY + plotJ) * scale - this.ctx.globalAlpha = 1; + this.ctx.globalAlpha = 1 // Fetch and draw tile image - const swampLevel = cst.getLevel(map.passability[idxVal]); - const tileImg = this.imgs.tiles[swampLevel]; - if (!this.conf.doingRotate) this.ctx.drawImage(tileImg, cx, cy, scale, scale); - else this.ctx.drawImage(tileImg, cy, cx, scale, scale); + const swampLevel = cst.getLevel(map.passability[idxVal]) + const tileImg = this.imgs.tiles[swampLevel] + + //since tiles arent completely opaque + if (!this.conf.doingRotate) this.ctx.clearRect(cx, cy, scale + .5, scale + .5) + else this.ctx.clearRect(cx, cy, scale + .5, scale + .5) + + //+1 is so that there arent gaps in the map + if (!this.conf.doingRotate) this.ctx.drawImage(tileImg, cx, cy, scale + .5, scale + .5) + else this.ctx.drawImage(tileImg, cy, cx, scale + .5, scale + .5) // Draw grid if (this.conf.showGrid) { - this.ctx.strokeStyle = 'gray'; - this.ctx.globalAlpha = 1; - if (!this.conf.doingRotate) this.ctx.strokeRect(cx, cy, scale, scale); - else this.ctx.strokeRect(cy, cx, scale, scale); + this.ctx.strokeStyle = 'gray' + this.ctx.globalAlpha = 1 + if (!this.conf.doingRotate) this.ctx.strokeRect(cx, cy, scale, scale) + else this.ctx.strokeRect(cy, cx, scale, scale) } } - // draw hover box last + this.ctx.restore() + } + + private renderHoverBox(world: GameWorld) { if (this.hoverPos != null) { - const {x, y} = this.hoverPos; - const cx = (minX+x)*scale, cy = (minY+(height-y-1))*scale; - this.ctx.strokeStyle = 'purple'; - this.ctx.lineWidth *= 2; - this.ctx.globalAlpha = 1; - if (!this.conf.doingRotate) this.ctx.strokeRect(cx, cy, scale, scale); - else this.ctx.strokeRect(cy, cx, scale, scale); + this.ctx.save() + this.ctx.fillStyle = "white" + this.ctx.globalAlpha = 1 + + let minX = world.minCorner.x + let minY = world.minCorner.y + let width = world.maxCorner.x - world.minCorner.x + let height = world.maxCorner.y - world.minCorner.y + + const scale = 20 + + this.ctx.scale(1 / scale, 1 / scale) + const { x, y } = this.hoverPos + const cx = (minX + x) * scale, cy = (minY + (height - y - 1)) * scale + this.ctx.strokeStyle = 'purple' + this.ctx.lineWidth *= 2 + this.ctx.globalAlpha = 1 + if (!this.conf.doingRotate) this.ctx.strokeRect(cx, cy, scale, scale) + else this.ctx.strokeRect(cy, cx, scale, scale) + this.ctx.restore() } - - this.ctx.restore(); } private renderResources(world: GameWorld) { - this.ctx.save(); - this.ctx.globalAlpha = 1; + this.ctx.save() + this.ctx.globalAlpha = 1 - let minX = world.minCorner.x; - let minY = world.minCorner.y; - let width = world.maxCorner.x - world.minCorner.x; - let height = world.maxCorner.y - world.minCorner.y; + let minX = world.minCorner.x + let minY = world.minCorner.y + let width = world.maxCorner.x - world.minCorner.x + let height = world.maxCorner.y - world.minCorner.y - const leadImg = this.imgs.resources.lead; - const goldImg = this.imgs.resources.gold; + const leadImg = this.imgs.resources.lead + const goldImg = this.imgs.resources.gold - const map = world.mapStats; - const scale = 1; + const map = world.mapStats + const scale = 1 const sigmoid = (x) => { - return 1 / (1 + Math.exp(-x)) + return 1 / (1 + Math.exp(-x)) } - for (let i = 0; i < width; i++) for (let j = 0; j < height; j++){ - let idxVal = map.getIdx(i,j); - let plotJ = height-j-1; + for (let i = 0; i < width; i++) for (let j = 0; j < height; j++) { + let idxVal = map.getIdx(i, j) + let plotJ = height - j - 1 - this.ctx.globalAlpha = 1; - const cx = (minX+i)*scale, cy = (minY+plotJ)*scale; + this.ctx.globalAlpha = 1 + const cx = (minX + i) * scale, cy = (minY + plotJ) * scale - if(map.goldVals[idxVal] > 0){ - let size = sigmoid(map.goldVals[idxVal] / 50); - if (!this.conf.doingRotate) this.ctx.drawImage(goldImg, cx + (1-size)/2, cy + (1-size)/2, scale * size, scale * size); - else this.ctx.drawImage(goldImg, cy + (1-size)/2, cx + (1-size)/2, scale * size, scale * size); + if (map.goldVals[idxVal] > 0) { + let size = sigmoid(map.goldVals[idxVal] / 50) + if (!this.conf.doingRotate) this.ctx.drawImage(goldImg, cx + (1 - size) / 2, cy + (1 - size) / 2, scale * size, scale * size) + else this.ctx.drawImage(goldImg, cy + (1 - size) / 2, cx + (1 - size) / 2, scale * size, scale * size) + + + this.ctx.strokeStyle = 'gold' + this.ctx.lineWidth = 1 / 30 + if (!this.conf.doingRotate) this.ctx.strokeRect(cx + .05, cy + .05, scale * .9, scale * .9) + else this.ctx.strokeRect(cy + .05, cx + .05, scale * .9, scale * .9) } - if(map.leadVals[idxVal] > 0){ - let size = sigmoid(map.leadVals[idxVal] / 50); - if (!this.conf.doingRotate) this.ctx.drawImage(leadImg, cx + (1-size)/2, cy + (1-size)/2, scale * size, scale * size); - else this.ctx.drawImage(leadImg, cy + (1-size)/2, cx + (1-size)/2, scale * size, scale * size); + if (map.leadVals[idxVal] > 0) { + let size = sigmoid(map.leadVals[idxVal] / 50) + if (!this.conf.doingRotate) this.ctx.drawImage(leadImg, cx + (1 - size) / 2, cy + (1 - size) / 2, scale * size, scale * size) + else this.ctx.drawImage(leadImg, cy + (1 - size) / 2, cx + (1 - size) / 2, scale * size, scale * size) + + this.ctx.strokeStyle = '#59727d' + this.ctx.lineWidth = 1 / 30 + if (!this.conf.doingRotate) this.ctx.strokeRect(cx + .05, cy + .05, scale * .9, scale * .9) + else this.ctx.strokeRect(cy + .05, cx + .05, scale * .9, scale * .9) } } - this.ctx.restore(); + this.ctx.restore() } private renderBodies(world: GameWorld, curTime: number, nextStep?: NextStep, lerpAmount?: number) { - const bodies = world.bodies; - const length = bodies.length; - const types = bodies.arrays.type; - const teams = bodies.arrays.team; - const hps = bodies.arrays.hp; - const ids = bodies.arrays.id; - const xs = bodies.arrays.x; - const ys = bodies.arrays.y; - const abilities = bodies.arrays.ability; - const minY = world.minCorner.y; - const maxY = world.maxCorner.y -1; - - let nextXs: Int32Array, nextYs: Int32Array, realXs: Float32Array, realYs: Float32Array; + const bodies = world.bodies + const length = bodies.length + const types = bodies.arrays.type + const teams = bodies.arrays.team + const hps = bodies.arrays.hp + const ids = bodies.arrays.id + const xs = bodies.arrays.x + const ys = bodies.arrays.y + const abilities = bodies.arrays.ability + const minY = world.minCorner.y + const maxY = world.maxCorner.y - 1 + + let nextXs: Int32Array, nextYs: Int32Array, realXs: Float32Array, realYs: Float32Array if (nextStep && lerpAmount) { - nextXs = nextStep.bodies.arrays.x; - nextYs = nextStep.bodies.arrays.y; - lerpAmount = lerpAmount || 0; + nextXs = nextStep.bodies.arrays.x + nextYs = nextStep.bodies.arrays.y + lerpAmount = lerpAmount || 0 } // Calculate the real xs and ys @@ -200,13 +233,13 @@ export default class Renderer { if (nextStep && lerpAmount) { // Interpolated // @ts-ignore - realXs[i] = xs[i] + (nextXs[i] - xs[i]) * lerpAmount; + realXs[i] = xs[i] + (nextXs[i] - xs[i]) * lerpAmount // @ts-ignore - realYs[i] = this.flip(ys[i] + (nextYs[i] - ys[i]) * lerpAmount, minY, maxY); + realYs[i] = this.flip(ys[i] + (nextYs[i] - ys[i]) * lerpAmount, minY, maxY) } else { // Not interpolated - realXs[i] = xs[i]; - realYs[i] = this.flip(ys[i], minY, maxY); + realXs[i] = xs[i] + realYs[i] = this.flip(ys[i], minY, maxY) } } @@ -214,17 +247,17 @@ export default class Renderer { // render images with priority last to have them be on top of other units. const drawEffect = (effect: string, x: number, y: number) => { - const effectImgs: HTMLImageElement[] = this.imgs.effects[effect]; - const whichImg = (Math.floor(curTime / cst.EFFECT_STEP) % effectImgs.length); - const effectImg = effectImgs[whichImg]; - this.drawBot(effectImg, x, y, 0); + const effectImgs: HTMLImageElement[] = this.imgs.effects[effect] + const whichImg = (Math.floor(curTime / cst.EFFECT_STEP) % effectImgs.length) + const effectImg = effectImgs[whichImg] + this.drawBot(effectImg, x, y, 0) } const renderBot = (i: number) => { - const img: HTMLImageElement = this.imgs.robots[cst.bodyTypeToString(types[i])][teams[i]]; - this.drawBot(img, realXs[i], realYs[i], hps[i]); + const img: HTMLImageElement = this.imgs.robots[cst.bodyTypeToString(types[i])][teams[i]] + this.drawBot(img, realXs[i], realYs[i], hps[i]) // TODO: draw bot - this.drawSightRadii(realXs[i], realYs[i], types[i], ids[i] === this.lastSelectedID); + this.drawSightRadii(realXs[i], realYs[i], types[i], ids[i] === this.lastSelectedID) // draw effect // TODO: handle abilities/actions @@ -232,17 +265,17 @@ export default class Renderer { // if (effect !== null) drawEffect(effect, realXs[i], realYs[i]); } - let priorityIndices: number[] = []; + let priorityIndices: number[] = [] for (let i = 0; i < length; i++) { - if(cst.bodyTypePriority.includes(types[i])){ - priorityIndices.push(i); - continue; + if (cst.bodyTypePriority.includes(types[i])) { + priorityIndices.push(i) + continue } - renderBot(i); + renderBot(i) } - priorityIndices.forEach((i) => renderBot(i)); + priorityIndices.forEach((i) => renderBot(i)) // Render empowered bodies // TODO: something similar for lead and gold @@ -256,7 +289,7 @@ export default class Renderer { // drawEffect(empowered_team[i] == 1 ? "empower_red" : "empower_blue", empowered_x[i], this.flip(empowered_y[i], minY, maxY)); // } - this.setInfoStringEvent(world, xs, ys); + this.setInfoStringEvent(world, xs, ys) } /** @@ -267,19 +300,19 @@ export default class Renderer { * yMax coordinate of the maximum edge */ private flip(y: number, yMin: number, yMax: number) { - return yMin + yMax - y; + return yMin + yMax - y } /** * Draws a cirlce centered at (x,y) with given squared radius and color. */ private drawBotRadius(x: number, y: number, radiusSquared: number, color: string) { - if (this.conf.doingRotate) [x,y] = [y,x]; - this.ctx.beginPath(); - this.ctx.arc(x+0.5, y+0.5, Math.sqrt(radiusSquared), 0, 2 * Math.PI); - this.ctx.strokeStyle = color; - this.ctx.lineWidth = cst.SIGHT_RADIUS_LINE_WIDTH; - this.ctx.stroke(); + if (this.conf.doingRotate) [x, y] = [y, x] + this.ctx.beginPath() + this.ctx.arc(x + 0.5, y + 0.5, Math.sqrt(radiusSquared), 0, 2 * Math.PI) + this.ctx.strokeStyle = color + this.ctx.lineWidth = cst.SIGHT_RADIUS_LINE_WIDTH + this.ctx.stroke() } /** @@ -288,11 +321,11 @@ export default class Renderer { private drawSightRadii(x: number, y: number, type: schema.BodyType, single?: Boolean) { // handle bots with no radius here, if necessary if (this.conf.seeActionRadius || single) { - this.drawBotRadius(x, y, this.metadata.types[type].actionRadiusSquared, cst.ACTION_RADIUS_COLOR); + this.drawBotRadius(x, y, this.metadata.types[type].actionRadiusSquared, cst.ACTION_RADIUS_COLOR) } if (this.conf.seeVisionRadius || single) { - this.drawBotRadius(x, y, this.metadata.types[type].visionRadiusSquared, cst.VISION_RADIUS_COLOR); + this.drawBotRadius(x, y, this.metadata.types[type].visionRadiusSquared, cst.VISION_RADIUS_COLOR) } } @@ -300,63 +333,63 @@ export default class Renderer { * Draws an image centered at (x, y) with the given radius */ private drawImage(img: HTMLImageElement, x: number, y: number, radius: number) { - if (this.conf.doingRotate) [x,y] = [y,x]; - this.ctx.drawImage(img, x-radius, y-radius, radius*2, radius*2); + if (this.conf.doingRotate) [x, y] = [y, x] + this.ctx.drawImage(img, x - radius, y - radius, radius * 2, radius * 2) } /** * Draws an image centered at (x, y), such that an image with default size covers a 1x1 cell */ private drawBot(img: HTMLImageElement, x: number, y: number, c: number) { - if (this.conf.doingRotate) [x,y] = [y,x]; - let realWidth = img.naturalWidth/cst.IMAGE_SIZE; - let realHeight = img.naturalHeight/cst.IMAGE_SIZE; + if (this.conf.doingRotate) [x, y] = [y, x] + let realWidth = img.naturalWidth / cst.IMAGE_SIZE + let realHeight = img.naturalHeight / cst.IMAGE_SIZE const sigmoid = (x) => { - return 1 / (1 + Math.exp(-x)) + return 1 / (1 + Math.exp(-x)) } //this.ctx.filter = `brightness(${sigmoid(c - 100) * 30 + 90}%)`; - let size = sigmoid(c / 100) * 1 + 0.3; - this.ctx.drawImage(img, x+(1-realWidth * size)/2, y+(1-realHeight * size)/2, realWidth * size, realHeight * size); + let size = sigmoid(c / 100) * 1 + 0.3 + this.ctx.drawImage(img, x + (1 - realWidth * size) / 2, y + (1 - realHeight * size) / 2, realWidth * size, realHeight * size) } private setInfoStringEvent(world: GameWorld, xs: Int32Array, ys: Int32Array) { // world information - const width = world.maxCorner.x - world.minCorner.x; - const height = world.maxCorner.y - world.minCorner.y; - const ids: Int32Array = world.bodies.arrays.id; + const width = world.maxCorner.x - world.minCorner.x + const height = world.maxCorner.y - world.minCorner.y + const ids: Int32Array = world.bodies.arrays.id // TODO: why is this Int8Array and not Int32Array? - const types: Int8Array = world.bodies.arrays.type; + const types: Int8Array = world.bodies.arrays.type // const radii: Float32Array = world.bodies.arrays.radius; - const onRobotSelected = this.onRobotSelected; + const onRobotSelected = this.onRobotSelected this.canvas.onmousedown = (event: MouseEvent) => { - const {x, y} = this.getIntegerLocation(event, world); + const { x, y } = this.getIntegerLocation(event, world) // Get the ID of the selected robot - let selectedRobotID; - let possiblePriorityID: number | undefined = undefined; + let selectedRobotID + let possiblePriorityID: number | undefined = undefined for (let i in ids) { if (xs[i] == x && ys[i] == y) { - selectedRobotID = ids[i]; - if(cst.bodyTypePriority.includes(types[i])) - possiblePriorityID = ids[i]; + selectedRobotID = ids[i] + if (cst.bodyTypePriority.includes(types[i])) + possiblePriorityID = ids[i] } } // if there are two robots in same cell, choose the one with priority - if(possiblePriorityID != undefined) selectedRobotID = possiblePriorityID; + if (possiblePriorityID != undefined) selectedRobotID = possiblePriorityID // Set the info string even if the robot is undefined - this.lastSelectedID = selectedRobotID; - onRobotSelected(selectedRobotID); - }; + this.lastSelectedID = selectedRobotID + onRobotSelected(selectedRobotID) + } } private setMouseoverEvent(world: GameWorld) { // world information // const width = world.maxCorner.x - world.minCorner.x; // const height = world.maxCorner.y - world.minCorner.y; - const onMouseover = this.onMouseover; + const onMouseover = this.onMouseover // const minY = world.minCorner.y; // const maxY = world.maxCorner.y - 1; @@ -366,99 +399,99 @@ export default class Renderer { // const y = this.flip(_y, minY, maxY) // Set the location of the mouseover - const {x,y} = this.getIntegerLocation(event, world); - const xrel = x - world.minCorner.x; - const yrel = y - world.minCorner.y; - const idx = world.mapStats.getIdx(xrel, yrel); - onMouseover(x, y, xrel, yrel, world.mapStats.passability[idx]); - this.hoverPos = {x: xrel, y: yrel}; - }; + const { x, y } = this.getIntegerLocation(event, world) + const xrel = x - world.minCorner.x + const yrel = y - world.minCorner.y + const idx = world.mapStats.getIdx(xrel, yrel) + onMouseover(x, y, xrel, yrel, world.mapStats.passability[idx]) + this.hoverPos = { x: xrel, y: yrel } + } this.canvas.onmouseout = (event) => { - this.hoverPos = null; - }; + this.hoverPos = null + } } private getIntegerLocation(event: MouseEvent, world: GameWorld) { - const width = world.maxCorner.x - world.minCorner.x; - const height = world.maxCorner.y - world.minCorner.y; - const minY = world.minCorner.y; - const maxY = world.maxCorner.y - 1; - var _x: number; - var _y: number; + const width = world.maxCorner.x - world.minCorner.x + const height = world.maxCorner.y - world.minCorner.y + const minY = world.minCorner.y + const maxY = world.maxCorner.y - 1 + var _x: number + var _y: number if (!this.conf.doingRotate) { - _x = width * event.offsetX / this.canvas.offsetWidth + world.minCorner.x; - _y = height * event.offsetY / this.canvas.offsetHeight + world.minCorner.y; + _x = width * event.offsetX / this.canvas.offsetWidth + world.minCorner.x + _y = height * event.offsetY / this.canvas.offsetHeight + world.minCorner.y _y = this.flip(_y, minY, maxY) } else { - _y = (world.maxCorner.y - world.minCorner.y - 1) - height * event.offsetX / this.canvas.offsetWidth + world.minCorner.y; - _x = width * event.offsetY / this.canvas.offsetHeight + world.minCorner.x; + _y = (world.maxCorner.y - world.minCorner.y - 1) - height * event.offsetX / this.canvas.offsetWidth + world.minCorner.y + _x = width * event.offsetY / this.canvas.offsetHeight + world.minCorner.x } - return {x: Math.floor(_x), y: Math.floor(_y+1)}; + return { x: Math.floor(_x), y: Math.floor(_y + 1) } } private renderIndicatorDotsLines(world: GameWorld) { if (!this.conf.indicators && !this.conf.allIndicators) { - return; + return } - const dots = world.indicatorDots; - const lines = world.indicatorLines; + const dots = world.indicatorDots + const lines = world.indicatorLines // Render the indicator dots - const dotsID = dots.arrays.id; - const dotsX = dots.arrays.x; - const dotsY = dots.arrays.y; - const dotsRed = dots.arrays.red; - const dotsGreen = dots.arrays.green; - const dotsBlue = dots.arrays.blue; - const minY = world.minCorner.y; - const maxY = world.maxCorner.y - 1; + const dotsID = dots.arrays.id + const dotsX = dots.arrays.x + const dotsY = dots.arrays.y + const dotsRed = dots.arrays.red + const dotsGreen = dots.arrays.green + const dotsBlue = dots.arrays.blue + const minY = world.minCorner.y + const maxY = world.maxCorner.y - 1 - console.log(dots.length); + console.log(dots.length) for (let i = 0; i < dots.length; i++) { if (dotsID[i] === this.lastSelectedID || this.conf.allIndicators) { - const red = dotsRed[i]; - const green = dotsGreen[i]; - const blue = dotsBlue[i]; - const x = dotsX[i]; - const y = this.flip(dotsY[i], minY, maxY); - - this.ctx.beginPath(); - this.ctx.arc(x+0.5, y+0.5, cst.INDICATOR_DOT_SIZE, 0, 2 * Math.PI, false); - this.ctx.fillStyle = `rgb(${red}, ${green}, ${blue})`; - this.ctx.fill(); + const red = dotsRed[i] + const green = dotsGreen[i] + const blue = dotsBlue[i] + const x = dotsX[i] + const y = this.flip(dotsY[i], minY, maxY) + + this.ctx.beginPath() + this.ctx.arc(x + 0.5, y + 0.5, cst.INDICATOR_DOT_SIZE, 0, 2 * Math.PI, false) + this.ctx.fillStyle = `rgb(${red}, ${green}, ${blue})` + this.ctx.fill() } } // Render the indicator lines - const linesID = lines.arrays.id; - const linesStartX = lines.arrays.startX; - const linesStartY = lines.arrays.startY; - const linesEndX = lines.arrays.endX; - const linesEndY = lines.arrays.endY; - const linesRed = lines.arrays.red; - const linesGreen = lines.arrays.green; - const linesBlue = lines.arrays.blue; - this.ctx.lineWidth = cst.INDICATOR_LINE_WIDTH; + const linesID = lines.arrays.id + const linesStartX = lines.arrays.startX + const linesStartY = lines.arrays.startY + const linesEndX = lines.arrays.endX + const linesEndY = lines.arrays.endY + const linesRed = lines.arrays.red + const linesGreen = lines.arrays.green + const linesBlue = lines.arrays.blue + this.ctx.lineWidth = cst.INDICATOR_LINE_WIDTH for (let i = 0; i < lines.length; i++) { if (linesID[i] === this.lastSelectedID || this.conf.allIndicators) { - const red = linesRed[i]; - const green = linesGreen[i]; - const blue = linesBlue[i]; - const startX = linesStartX[i]+0.5; - const startY = this.flip(linesStartY[i], minY, maxY)+0.5; - const endX = linesEndX[i]+0.5; - const endY = this.flip(linesEndY[i], minY, maxY)+0.5; - - this.ctx.beginPath(); - this.ctx.moveTo(startX, startY); - this.ctx.lineTo(endX, endY); - this.ctx.strokeStyle = `rgb(${red}, ${green}, ${blue})`; - this.ctx.stroke(); + const red = linesRed[i] + const green = linesGreen[i] + const blue = linesBlue[i] + const startX = linesStartX[i] + 0.5 + const startY = this.flip(linesStartY[i], minY, maxY) + 0.5 + const endX = linesEndX[i] + 0.5 + const endY = this.flip(linesEndY[i], minY, maxY) + 0.5 + + this.ctx.beginPath() + this.ctx.moveTo(startX, startY) + this.ctx.lineTo(endX, endY) + this.ctx.strokeStyle = `rgb(${red}, ${green}, ${blue})` + this.ctx.stroke() } } } diff --git a/client/visualizer/src/imageloader.ts b/client/visualizer/src/imageloader.ts index 0463b629..847efa0c 100644 --- a/client/visualizer/src/imageloader.ts +++ b/client/visualizer/src/imageloader.ts @@ -1,7 +1,7 @@ -import { basename } from 'path'; -import {Config} from './config'; -import * as cst from "./constants"; -type Image = HTMLImageElement; +import { basename } from 'path' +import { Config } from './config' +import * as cst from "./constants" +type Image = HTMLImageElement export type AllImages = { star: Image, @@ -15,8 +15,8 @@ export type AllImages = { watchtower: Array, }, resources: { - lead: Image, - gold: Image + lead: Image, + gold: Image } effects: { // TODO }, @@ -33,49 +33,49 @@ export type AllImages = { halveUPS: Image, goEnd: Image } -}; +} export function loadAll(config: Config, callback: (arg0: AllImages) => void) { - const dirname = "./static/img/"; + const dirname = "./static/img/" - const NEUTRAL: number = 0; - const RED: number = 1; - const BLU: number = 2; + const NEUTRAL: number = 0 + const RED: number = 1 + const BLU: number = 2 - function loadImage(obj, slot, path, src?) : void { - const f = loadImage; - f.expected++; - const image = new Image(); + function loadImage(obj, slot, path, src?): void { + const f = loadImage + f.expected++ + const image = new Image() - function onFinish(){ - if(f.requestedAll && f.expected == f.success + f.failure){ - console.log(`Total ${f.expected} images loaded: ${f.success} successful, ${f.failure} failed.`); - callback((Object.freeze(result) as unknown) as AllImages); + function onFinish() { + if (f.requestedAll && f.expected == f.success + f.failure) { + console.log(`Total ${f.expected} images loaded: ${f.success} successful, ${f.failure} failed.`) + callback((Object.freeze(result) as unknown) as AllImages) } } image.onload = () => { - obj[slot] = image; - f.success++; - onFinish(); - }; + obj[slot] = image + f.success++ + onFinish() + } image.onerror = () => { - obj[slot] = image; - f.failure++; - console.error(`CANNOT LOAD IMAGE: ${slot}, ${path}, ${image}`); - if(src) console.error(`Source: ${src}`); - onFinish(); + obj[slot] = image + f.failure++ + console.error(`CANNOT LOAD IMAGE: ${slot}, ${path}, ${image}`) + if (src) console.error(`Source: ${src}`) + onFinish() } // might want to use path library // webpack url loader triggers on require(".png"), so .png should be explicit - image.src = (src ? src : require(dirname + path + '.png').default); + image.src = (src ? src : require(dirname + path + '.png').default) } - loadImage.expected = 0; - loadImage.success = 0; - loadImage.failure = 0; - loadImage.requestedAll = false; + loadImage.expected = 0 + loadImage.success = 0 + loadImage.failure = 0 + loadImage.requestedAll = false const result = { tiles: [], @@ -114,79 +114,106 @@ export function loadAll(config: Config, callback: (arg0: AllImages) => void) { halveUPS: null, goEnd: null } - }; + } // helper function to manipulate images const htmlToData = (ele: HTMLImageElement): ImageData => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - if(!context) throw new Error("Error while converting a tile image"); - canvas.width = ele.width; - canvas.height = ele.height; - context.drawImage(ele, 0, 0); - return context.getImageData(0, 0, ele.width, ele.height); - }; + const canvas = document.createElement('canvas') + const context = canvas.getContext('2d') + if (!context) throw new Error("Error while converting a tile image") + canvas.width = ele.width + canvas.height = ele.height + context.drawImage(ele, 0, 0) + return context.getImageData(0, 0, ele.width, ele.height) + } const dataToSrc = (data: ImageData): String => { - var canvas = document.createElement("canvas"); - canvas.width = data.width; - canvas.height = data.height; - var context = canvas.getContext("2d"); - if(!context) throw new Error("Error while converting a tile images"); - context.putImageData(data, 0, 0); - - return canvas.toDataURL(`edited.png`); - }; + var canvas = document.createElement("canvas") + canvas.width = data.width + canvas.height = data.height + var context = canvas.getContext("2d") + if (!context) throw new Error("Error while converting a tile images") + context.putImageData(data, 0, 0) + + return canvas.toDataURL(`edited.png`) + } - loadImage(result, 'star', 'star'); + loadImage(result, 'star', 'star') // terrain tiles { - const tintData = (data: ImageData, colors: Uint8Array): ImageData => { - const arr = new Uint8ClampedArray(data.data.length); - for(let i=0; i 128; - const factor = rock ? 1.5 : 1; - arr[i + 0] = colors[0] / factor; - arr[i + 1] = colors[1] / factor; - arr[i + 2] = colors[2] / factor; - arr[i + 3] = 240; + // const tintData = (data: ImageData, colors: Uint8Array): ImageData => { + // const arr = new Uint8ClampedArray(data.data.length) + // for (let i = 0; i < arr.length; i += 4) { + // const rock = data.data[i] > 128; + // const factor = rock ? 1.5 : 1; + // arr[i + 0] = colors[0] / factor; + // arr[i + 1] = colors[1] / factor; + // arr[i + 2] = colors[2] / factor; + // arr[i + 3] = 240 + // } + // const result = new ImageData(arr, data.height) + // return result + // } + + const randomTile = (dim: number, colors: Uint8Array, level: number): ImageData => { + var seed = level + 1 //avoid 0 + function srand() { + var x = Math.sin(seed++) * 10000 + return x - Math.floor(x) } - const result = new ImageData(arr, data.height); - return result; - } - - const baseTile: Image = new Image(); - baseTile.src = require(dirname + 'tiles/terrain.png').default; - const nLev = cst.TILE_COLORS.length; - baseTile.onload = () => { - for(let i=0; icst.TILE_COLORS[i]); - const path: String = dataToSrc(tinted); - loadImage(result.tiles, i, "", path.slice(0, path.length-4)); + const arr = new Uint8ClampedArray(dim ** 2 * 4) + for (let i = 0; i < arr.length; i += 4) { + var scale = 8 * (2 + level) / 255 + var shade = srand() * scale + 1 - scale; + arr[i + 0] = colors[level][0] * shade + arr[i + 1] = colors[level][1] * shade + arr[i + 2] = colors[level][2] * shade + arr[i + 3] = 255 } + const result = new ImageData(arr, dim) + return result + + } + + // const baseTile: Image = new Image() + // baseTile.src = require(dirname + 'tiles/terrain3.png').default + + const nLev = cst.TILE_COLORS.length + // baseTile.onload = () => { + // for (let i = 0; i < nLev; i++) { + // const data: ImageData = htmlToData(baseTile) + // const tinted: ImageData = randomTile(25, cst.TILE_COLORS, i) + // const path: String = dataToSrc(tinted) + // loadImage(result.tiles, i, "", path.slice(0, path.length - 4)) + // } + // } + + for (let i = 0; i < nLev; i++) { + const tinted: ImageData = randomTile(25, cst.TILE_COLORS, i) + const path: String = dataToSrc(tinted) + loadImage(result.tiles, i, "", path.slice(0, path.length - 4)) } } // robot sprites - loadImage(result.robots.archon, RED, 'robots/red_archon_portable'); - loadImage(result.robots.watchtower, RED, 'robots/red_watchtower'); - loadImage(result.robots.builder, RED, 'robots/red_builder'); - loadImage(result.robots.miner, RED, 'robots/red_miner'); - loadImage(result.robots.sage, RED, 'robots/red_sage'); - loadImage(result.robots.soldier, RED, 'robots/red_soldier'); - loadImage(result.robots.laboratory, RED, 'robots/red_lab'); - - loadImage(result.robots.archon, BLU, 'robots/blue_archon_portable'); - loadImage(result.robots.watchtower, BLU, 'robots/blue_watchtower'); - loadImage(result.robots.builder, BLU, 'robots/blue_builder'); - loadImage(result.robots.miner, BLU, 'robots/blue_miner'); - loadImage(result.robots.sage, BLU, 'robots/blue_sage'); - loadImage(result.robots.soldier, BLU, 'robots/blue_soldier'); - loadImage(result.robots.laboratory, BLU, 'robots/blue_lab'); - - loadImage(result.resources, 'lead', 'star'); - loadImage(result.resources, 'gold', 'star'); + loadImage(result.robots.archon, RED, 'robots/red_archon_portable') + loadImage(result.robots.watchtower, RED, 'robots/red_watchtower') + loadImage(result.robots.builder, RED, 'robots/red_builder') + loadImage(result.robots.miner, RED, 'robots/red_miner') + loadImage(result.robots.sage, RED, 'robots/red_sage') + loadImage(result.robots.soldier, RED, 'robots/red_soldier') + loadImage(result.robots.laboratory, RED, 'robots/red_lab') + + loadImage(result.robots.archon, BLU, 'robots/blue_archon_portable') + loadImage(result.robots.watchtower, BLU, 'robots/blue_watchtower') + loadImage(result.robots.builder, BLU, 'robots/blue_builder') + loadImage(result.robots.miner, BLU, 'robots/blue_miner') + loadImage(result.robots.sage, BLU, 'robots/blue_sage') + loadImage(result.robots.soldier, BLU, 'robots/blue_soldier') + loadImage(result.robots.laboratory, BLU, 'robots/blue_lab') + + loadImage(result.resources, 'lead', 'resources/lead') + loadImage(result.resources, 'gold', 'resources/gold') // loadImage(result.robots.enlightenmentCenter, NEUTRAL, 'robots/center'); @@ -199,79 +226,79 @@ export function loadAll(config: Config, callback: (arg0: AllImages) => void) { { const makeTransparent = (data: ImageData): ImageData => { - const arr = new Uint8ClampedArray(data.data.length); - for(let i=0; i { - const arr = new Uint8ClampedArray(data.data.length); - for(let i=0; i { - const arr = new Uint8ClampedArray(data.data.length); - for(let i=0; i { - const data: ImageData = htmlToData(base); - const trans: ImageData = makeTransparent(data); - const red: ImageData = makeRed(trans); - const blue: ImageData = makeBlue(trans); - const path_red: String = dataToSrc(red); - const path_blue: String = dataToSrc(blue); - loadImage(result.effects.empower_red, i, "", path_red.slice(0, path_red.length-4)); - loadImage(result.effects.empower_blue, i, "", path_blue.slice(0, path_blue.length-4)); + const data: ImageData = htmlToData(base) + const trans: ImageData = makeTransparent(data) + const red: ImageData = makeRed(trans) + const blue: ImageData = makeBlue(trans) + const path_red: String = dataToSrc(red) + const path_blue: String = dataToSrc(blue) + loadImage(result.effects.empower_red, i, "", path_red.slice(0, path_red.length - 4)) + loadImage(result.effects.empower_blue, i, "", path_blue.slice(0, path_blue.length - 4)) } } } - loadImage(result.effects.expose, 0, 'effects/expose/expose_empty'); + loadImage(result.effects.expose, 0, 'effects/expose/expose_empty') - loadImage(result.effects.camouflage_red, 0, 'effects/camouflage/camo_red'); - loadImage(result.effects.camouflage_blue, 0, 'effects/camouflage/camo_blue'); + loadImage(result.effects.camouflage_red, 0, 'effects/camouflage/camo_red') + loadImage(result.effects.camouflage_blue, 0, 'effects/camouflage/camo_blue') // buttons are from https://material.io/resources/icons - loadImage(result.controls, 'goNext', 'controls/go-next'); - loadImage(result.controls, 'goPrevious', 'controls/go-previous'); - loadImage(result.controls, 'playbackPause', 'controls/playback-pause'); - loadImage(result.controls, 'playbackStart', 'controls/playback-start'); - loadImage(result.controls, 'playbackStop', 'controls/playback-stop'); - loadImage(result.controls, 'reverseUPS', 'controls/reverse'); - loadImage(result.controls, 'doubleUPS', 'controls/skip-forward'); - loadImage(result.controls, 'halveUPS', 'controls/skip-backward'); - loadImage(result.controls, 'goEnd', 'controls/go-end'); - - loadImage(result.controls, 'matchBackward', 'controls/green-previous'); - loadImage(result.controls, 'matchForward', 'controls/green-next'); - + loadImage(result.controls, 'goNext', 'controls/go-next') + loadImage(result.controls, 'goPrevious', 'controls/go-previous') + loadImage(result.controls, 'playbackPause', 'controls/playback-pause') + loadImage(result.controls, 'playbackStart', 'controls/playback-start') + loadImage(result.controls, 'playbackStop', 'controls/playback-stop') + loadImage(result.controls, 'reverseUPS', 'controls/reverse') + loadImage(result.controls, 'doubleUPS', 'controls/skip-forward') + loadImage(result.controls, 'halveUPS', 'controls/skip-backward') + loadImage(result.controls, 'goEnd', 'controls/go-end') + + loadImage(result.controls, 'matchBackward', 'controls/green-previous') + loadImage(result.controls, 'matchForward', 'controls/green-next') + // mark as finished - loadImage.requestedAll = true; + loadImage.requestedAll = true } diff --git a/client/visualizer/src/static/img/resources/gold.png b/client/visualizer/src/static/img/resources/gold.png new file mode 100644 index 0000000000000000000000000000000000000000..ed786d2563bd5fccb3339a7cb7cd303e3f071941 GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~yTEL88gA|sYUcVZstk=`UF(iZa z?R3Y!!wNjEol}y}E}A|g_?+sl8Ofnu*=oy?A<{sweRA5wT zV41)mP&b-O z>$?oo_Ohos6M0Qe9$mZW#H#pAqrEO>4{R3{yIIb>W^BY`qpo7Fe|MsH!b6}-v2V2{NT?0!n?|kzs{*>ztZj&4%?@tVTaOs+m z;rUa`4=nXKY4-cS>YvHgq94Qrcd7q5S=HiJ17Jp!Rg@2y3Vl@W=@cHYv_Jpadr3aIJ-LvJ@3L_PxsD?)2 z`#rmNZGG`BP{{Pbkzl!5C*HBGediUq;P?*KIqO$W}QS&oez&GQBOc-}{nwx%LBHr4s*tCwBE_Kly33!wnRa fkZ?WF#PW~Pd3v4r$2DIqKoREY>gTe~DWM4f|8(Hv literal 0 HcmV?d00001 diff --git a/client/visualizer/src/static/img/tiles/terrain2.png b/client/visualizer/src/static/img/tiles/terrain2.png new file mode 100644 index 0000000000000000000000000000000000000000..c20a1cf74389990dda60d412e602da0792c11daa GIT binary patch literal 3016 zcmV;(3pezMP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91GN1zh1ONa40RR91G5`Po0Cmf+s{jBCGD$>1RA>dQ+1H9xTM!1|-R+nY z;tL6iIR_BDaL^mQ^hxwWOo-@>2<9A~$$&XKXMg4V?V_ihqhP`Am8$-VYwgg3_3PKq zeE+MfFTS(Gcz+I18buH2@mHO$=L*B;lhR8vSrJ< z6)RSB@7}$uc>zj5V55JbcL<09=>7Zm)qef@wVaD0lMIN%9BbFCbHsXh7|THP;lqdG z=a_XZ`j>jk5r(CFD4^)`=g-~k+qVt7hYufCJO0CA29w3lFxgKY%pFXWMJdDH_GRH_xCCW+^wqRJl ze*Jottuj+?N)1_aMXw;hfu{INZiy(UPfU9>+NP^5x5J&6+iH^pYp%LL6q7@&D-^CK3cw_uIE`?{3|?)ur9P ze}5S&DvV*Yve16|^r__95@GD!yLY>N`}S3P;J|?jianE{$yj7ou3SldWelD&wax)L z{zUIofPr#^@csMuyRBQdR(WX=2ShBXXDt30Lzy{>l_e)`+_=$g+_; zb7G1QI=%PxF^`#ZgZ4I4Jh#7L1zU*z0Z0GJo?WF}zA zigBX);K74Y24sd)yLRoW)?R@hxwmiMj`06aZw?N7FXi6q9qp0Ui9~}FhycQ)&&jOG zK-NVpdt%$RZ5^kS7iTz?gMrZ~L5dSKIXkZ(+{io11;u=;mwcUbaYCdppqv`|nTr$V zQ0ovUL@JSU6SX&-elkI}#dm@kGoqbu^`;C3ffES|z4V~Smm`#jj!DEZmm@ZmIf`7I zb4&t7BE=a8MIy)v&Lt3ZtX{pk1jV70mv+mRErn+tCSzgH0bg*8V>q6a5*d6b51!#8Clm0M zuS%%ODDM7;V4T4mQeJVw9EEt}5E*^O+vvb^sssnWjh+CJX^n&WcAarih9`YITA&d z1Y66dWCS*6WqYWTNa3em0|-xy50H5Vu3fvfTJwxG$8jn`*IdS4dIi>EcF<4MsaFK}O zb)mm`|0sd}hb-(tzw>|Qy`N-+i(wZoT)P83pR~7B5H5%gC!& zuPQJCb>+&H%9JdlM4E&6ktlo5hp*rA(8~rbTE2XF@eC6&0t^8r^3&7P6*&<%hpz1{RMA zBmx8|1jvcJK(#&lWReg@)b?MW|L7B97*~m6?@Li}vJPF7m zW`J76fB;cqESi*s5)6)Ip7Y5>_+q4JI<4q|hnGJ6=+<{Y96x@%=3!V1vA@R|*2Xd! z!{TiVWX^qRi%&5tOJpv4S5b7#c%nqdAh%i4!&1|HL6^dMhi-C;KDP{ zX--&IZh4s^3)3Z7(LEdorvOvtF^UZEoLay+B~p~Ru{mbR2|!CSgsj6>g7CcQWzWTU zxb!Gnd&-z|J~YHxE&139m(J1Gc#9&5^j(N?qC5%QH)5ZBY)TIM!k#u|mCU&5S;Oml zS57?{PLPxgKP zmX_0WqZXTP#IZrY!DeD)&CdQXE;+%v zWt?-$#%YyPF=do!2d8c6&pxD!Q&X~$n$r(4A{(mBMnJTT$ET!PXUzdOuUwr%?l+0F zGD~KZ7blV#<(ELx(FQN}n2)V=pwTB&ibWH%MQM~B1_B!g4}i5~5^w7?tVGg(in%{H zjbcby(f`0pbh8#LYl4GfpN!y3iA}X$rk^OZ;8_Enb>JLUT3Vp^D9~ERpHnJFDTDCh zi?MOS8VZ&^oCMSu?;Ke`DBkI3Za#4D(7+)&KpQzY zZBQaZ5B-s?2Py+ZX=r>df>L_s%$fQ$BT}wp%e}*C6<*FE#veR*aCFCx979~FovVrd zC#O>I@aUuH%y`h>cxD)l2?bccozu@6hg)#GXdK))iX5%k$UnJ%{RVejACB?0Us6AN zbO=~E5@jvZIDm1h2ye!bv+0p?1D!i)d_ literal 0 HcmV?d00001 diff --git a/client/visualizer/src/static/img/tiles/terrain3.png b/client/visualizer/src/static/img/tiles/terrain3.png new file mode 100644 index 0000000000000000000000000000000000000000..3a31974a353047e9e59acd1efe65faa203b5a1f9 GIT binary patch literal 2473 zcmV;a30C%rP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91DWC%Y1ONa40RR91DF6Tf0Kg!GUjP6J6G=otR9Fd3*jZB)K@bGs-eHkL zkV_Fn4doU7|IhH1Ae4}hLvBToOJLovB9fpZ#@Xra%F4{D9(L`0{rYtARMfiluO`u#vdv@W_ zaY-TzoaB%TS!)0!5S&9HnP+765`lYrd(~e*fBvlf^Yimn9ppKq4SxLiQ3hxuqKQNT z8Dx!vgM;EDhbkL=!3ZHE8HbRQ90?^rngb5N?(S|SB+Q({C8=0(@RV?Wf4};WI}*Yp z(*E=@0SGb(S%*k|`#j4{bZ@9`kdjKuA&%yd09ajJE!ElrfHixpDK+p9A3i*ZB)}e` z900E_f<41`w~nx!4AR4Jw15GddFFaUdk37N2mzCT1nMyYT!58A8SR%?`OJ&4Uz~Za zx)2~j*DXx~nF)(Xxg#Z*Ywi*eV{qu>$B#u0xWrLq-5M?Gu;M;*p$rJ$4e>fB-iE8&n9E+@C$`X#)uy41|`sMelu=>? zkm5EG2*XlJ@nQ+LP6%T1z_N$C_LYf4;DH0-#cBcxgebc&6LOiyflxS1V4C=jvb-MHYqQ~=60jeT9{iw2OVJg0z0cqvjFIVE|&m03s3f)&=SlBOui;LtrAsamV*a#9hja zkTSzVLOT(H1RVIv@0p88$&(h7uQ#myzy`MFbzwmOg_QXoD3KCSFPQ|^T;7@7IA0Kl_ciaLh0Z_wdfruc4m_ToZ}% zIq#Vf_8A;hVg!s-fVdbSh9Ksc?If;-ol+r#xoUta>vppOr@F6Cl z)>X)w-qach$Vpss$rpDCGGFgz%qaoPNgMSHr+}J6)Ch=^ju4lTO%;&$nM+9d>;xl% zXv!xaGI{+VB#(I&a3N<-PxgHXv zB273lNWk+|jwr6lZ?BesDaPJmzV68>YB`fH0F(*<5_R^wkVX_aPWz2xzhs0(tT+cs z3>@!K#yE85#2bVmW@r_!Joxt3-)=y9L^4V#w3r}wFKi_OiXeq?k!yt62gil5N|=M^ z4j(aQ5aWWweV@(Cfe#*tyE^{>P59*U6yXbm|-QhN~MnrDKD5hIVi z_84-Qlh2Pb&v3yb(4VXXh|wXz1s5=ioIHbTfVgX&0|5Nq_Sqa40COoKtcfMomA$HF zo**%*;1$GaqI?_Yru{Br2MlY%(suLBS&k)~p0Wu-`2=UjS|<4WQ3IRvds z031=o%pqXp?SWuUv_0Wq4`GI!dbj?Yg(DW&iySAMWF*a5cX!$h;Di7mD#RoP%oQ(x zYw7bGKA1Upu;e2uj*B-3lOQ?j=R?XPDCKf@#R=t=AdVpJIlYPmk_Z^~6Q&io?H!yG zixgZW@_afzPy8h1D#iS;CqP>f{xFFnbSM9keYu||G? nnacqaUxbE4IqWAjJ`DR0Z~A=K_flv-00000NkvXXu0mjf>