├── src ├── assets │ ├── .gitkeep │ ├── img │ │ ├── logo-simple.png │ │ ├── logo-small.png │ │ ├── e11-logo-dark.png │ │ ├── metamask-e11.png │ │ ├── metamask-fox.png │ │ ├── metamask-lock.png │ │ ├── metamask-oops.png │ │ ├── bg_resource_e11.png │ │ ├── bg_resource_gold.png │ │ ├── bg_resource_crystal.png │ │ ├── bg_resource_quantum.png │ │ ├── units │ │ │ └── thumbnails │ │ │ │ ├── archer.png │ │ │ │ ├── guardian.png │ │ │ │ └── tiny_warrior.png │ │ └── buildings │ │ │ └── thumbnails │ │ │ ├── barracks_1.png │ │ │ ├── barracks_2.png │ │ │ ├── barracks_3.png │ │ │ ├── portal_1.png │ │ │ ├── portal_2.png │ │ │ ├── portal_3.png │ │ │ ├── experiment_1.png │ │ │ ├── gold_mine_1.png │ │ │ ├── gold_mine_2.png │ │ │ ├── gold_mine_3.png │ │ │ ├── gold_mine_4.png │ │ │ ├── gold_mine_5.png │ │ │ ├── city_center_1.png │ │ │ ├── city_center_2.png │ │ │ ├── city_center_3.png │ │ │ ├── crystal_mine_1.png │ │ │ ├── crystal_mine_2.png │ │ │ ├── crystal_mine_3.png │ │ │ ├── crystal_mine_4.png │ │ │ ├── crystal_mine_5.png │ │ │ ├── gold_factory_1.png │ │ │ ├── gold_factory_2.png │ │ │ ├── gold_factory_3.png │ │ │ ├── gold_factory_4.png │ │ │ ├── gold_factory_5.png │ │ │ ├── gold_storage_1.png │ │ │ ├── gold_storage_2.png │ │ │ ├── gold_storage_3.png │ │ │ ├── crystal_factory_1.png │ │ │ ├── crystal_factory_2.png │ │ │ ├── crystal_factory_3.png │ │ │ ├── crystal_factory_4.png │ │ │ ├── crystal_factory_5.png │ │ │ ├── crystal_storage_1.png │ │ │ ├── crystal_storage_2.png │ │ │ └── crystal_storage_3.png │ └── e11-theme │ │ ├── components │ │ ├── _icon.scss │ │ ├── _progress-bar.scss │ │ ├── _avatar.scss │ │ ├── _input.scss │ │ ├── _button.scss │ │ ├── _badge.scss │ │ └── _segments.scss │ │ ├── fonts │ │ ├── e11-font.eot │ │ ├── e11-font.ttf │ │ └── e11-font.woff │ │ ├── _mixins.scss │ │ ├── theme.scss │ │ └── _variables.scss ├── app │ ├── app.component.css │ ├── +admin │ │ ├── admin.component.scss │ │ └── admin.module.ts │ ├── +trades │ │ ├── trades.component.scss │ │ ├── trades.component.html │ │ ├── trades.component.ts │ │ └── trades.module.ts │ ├── +assets │ │ ├── +defense │ │ │ ├── defense.component.scss │ │ │ ├── defense.component.html │ │ │ └── defense.component.ts │ │ ├── +units │ │ │ └── units.component.scss │ │ ├── +research │ │ │ ├── research.component.scss │ │ │ ├── research.component.html │ │ │ └── research.component.ts │ │ ├── +buildings │ │ │ └── buildings.component.scss │ │ ├── assets.component.ts │ │ ├── assets.component.html │ │ ├── assets.component.scss │ │ ├── queue-navbar │ │ │ ├── queue-navbar.component.ts │ │ │ ├── queue-navbar.component.scss │ │ │ └── queue-navbar.component.html │ │ └── assets.module.ts │ ├── shared │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── mobile-screen │ │ │ │ ├── mobile-screen.component.html │ │ │ │ ├── mobile-screen.component.ts │ │ │ │ └── mobile-screen.component.scss │ │ │ ├── loading │ │ │ │ ├── loading.component.html │ │ │ │ ├── loading.component.ts │ │ │ │ └── loading.component.scss │ │ │ ├── errors │ │ │ │ ├── errors.component.ts │ │ │ │ └── errors.component.scss │ │ │ ├── navbar │ │ │ │ └── navbar.component.ts │ │ │ └── abstract-container.component.ts │ │ ├── pipes │ │ │ ├── round.pipe.ts │ │ │ ├── pipes.module.ts │ │ │ ├── large-number.pipe.ts │ │ │ ├── block-time.pipe.ts │ │ │ └── past-block-time.pipe.ts │ │ ├── guards │ │ │ └── bootstrap.guard.ts │ │ └── models │ │ │ ├── unit.model.ts │ │ │ └── building.model.ts │ ├── +battle │ │ ├── +target │ │ │ ├── target.component.scss │ │ │ └── target.component.html │ │ ├── +history │ │ │ ├── history.component.scss │ │ │ └── history.component.html │ │ ├── army-stats │ │ │ ├── army-stats.component.html │ │ │ ├── army-stats.component.scss │ │ │ └── army-stats.component.ts │ │ ├── battle.component.html │ │ ├── army-selection │ │ │ ├── army-selection.component.scss │ │ │ └── army-selection.component.html │ │ ├── battle.module.ts │ │ ├── battle.component.scss │ │ ├── targets-list │ │ │ └── targets-list.component.ts │ │ └── battle.component.ts │ ├── +dashboard │ │ ├── village-extras │ │ │ ├── village-extras.component.scss │ │ │ ├── village-extras.component.ts │ │ │ └── village-extras.component.html │ │ ├── dashboard.component.scss │ │ ├── village-queues │ │ │ ├── village-queues.component.scss │ │ │ └── village-queues.component.ts │ │ ├── dashboard.component.html │ │ ├── village-logs │ │ │ ├── village-logs.component.scss │ │ │ └── village-logs.component.ts │ │ ├── dashboard.module.ts │ │ └── village-info │ │ │ └── village-info.component.ts │ ├── +onboarding │ │ ├── onboarding.component.scss │ │ ├── onboarding.component.html │ │ ├── private-beta │ │ │ ├── private-beta.component.ts │ │ │ └── private-beta.component.html │ │ ├── onboarding.module.ts │ │ └── new-user │ │ │ ├── new-user.component.ts │ │ │ └── new-user.component.scss │ ├── app.actions.ts │ ├── app.component.html │ ├── app.selectors.ts │ ├── app.state.ts │ └── app.effects.ts ├── favicon.ico ├── styles.scss ├── core │ ├── web3 │ │ ├── transaction.model.ts │ │ ├── web3.state.ts │ │ └── web3.module.ts │ ├── player │ │ ├── army │ │ │ ├── player-army.state.ts │ │ │ ├── player-army.actions.ts │ │ │ └── player-army.reducer.ts │ │ ├── assets │ │ │ ├── units │ │ │ │ ├── player-unit.model.ts │ │ │ │ ├── player-units.state.ts │ │ │ │ ├── player-units.reducer.ts │ │ │ │ ├── player-units.actions.ts │ │ │ │ └── player-units.service.ts │ │ │ └── buildings │ │ │ │ ├── player-building.model.ts │ │ │ │ ├── player-buildings.state.ts │ │ │ │ ├── player-buildings.reducer.ts │ │ │ │ ├── player-buildings.service.ts │ │ │ │ └── player-buildings.actions.ts │ │ ├── resources │ │ │ ├── player-resources.model.ts │ │ │ ├── player-resources.state.ts │ │ │ └── player-resources.actions.ts │ │ ├── targets │ │ │ ├── player-target.model.ts │ │ │ ├── player-targets.state.ts │ │ │ ├── player-targets.reducer.ts │ │ │ └── player-targets.service.ts │ │ ├── tokens │ │ │ ├── player-tokens.state.ts │ │ │ ├── player-tokens.reducer.ts │ │ │ └── player-tokens.actions.ts │ │ ├── village │ │ │ ├── player-village.state.ts │ │ │ ├── village-info.model.ts │ │ │ └── player-village.reducer.ts │ │ └── battle │ │ │ ├── player-battle.model.ts │ │ │ └── player-battle.state.ts │ ├── shared │ │ ├── util │ │ │ ├── helpers.ts │ │ │ ├── type.ts │ │ │ └── get-web3.ts │ │ └── status.model.ts │ └── assets │ │ ├── buildings │ │ ├── queue │ │ │ ├── queue-building.model.ts │ │ │ └── buildings-queue.state.ts │ │ └── data │ │ │ ├── buildings-data.state.ts │ │ │ ├── buildings-data.service.ts │ │ │ ├── buildings-data.reducer.ts │ │ │ ├── buildings-data.actions.ts │ │ │ └── data-building.model.ts │ │ ├── units │ │ ├── queue │ │ │ ├── queue-unit.model.ts │ │ │ ├── units-queue.state.ts │ │ │ ├── units-queue.reducer.ts │ │ │ └── units-queue.actions.ts │ │ └── data │ │ │ ├── units-data.state.ts │ │ │ ├── data-unit.model.ts │ │ │ ├── units-data.reducer.ts │ │ │ ├── units-data.actions.ts │ │ │ ├── units-data.service.ts │ │ │ └── units-data.effects.ts │ │ ├── requirements │ │ ├── assets-requirements.state.ts │ │ ├── assets-requirements.service.ts │ │ ├── assets-requirements.actions.ts │ │ ├── assets-requirements.reducer.ts │ │ └── assets-requirements.effects.ts │ │ └── assets.module.ts ├── typings.d.ts ├── tsconfig.app.json ├── main.ts ├── tsconfig.spec.json ├── environments │ ├── environment.poa.ts │ ├── environment.prod.ts │ ├── environment.ts │ └── environment.private.ts ├── index.html ├── test.ts ├── redirect-cryptowars-jp.html └── redirect-alpha-cryptowars-jp.html ├── data ├── test │ ├── buildings │ │ ├── barracks.json │ │ ├── portal.json │ │ ├── crystal_mine.json │ │ ├── gold_factory.json │ │ ├── gold_mine.json │ │ ├── gold_storage.json │ │ ├── crystal_factory.json │ │ ├── crystal_storage.json │ │ └── city_center.json │ ├── points.json │ ├── battle.json │ ├── resources.json │ └── units.json ├── preICO.json ├── production │ ├── points.json │ ├── battle.json │ ├── resources.json │ ├── buildings │ │ ├── gold_mine.json │ │ ├── portal.json │ │ ├── crystal_mine.json │ │ ├── gold_storage.json │ │ ├── crystal_storage.json │ │ ├── barracks.json │ │ ├── gold_factory.json │ │ ├── crystal_factory.json │ │ └── city_center.json │ └── units.json ├── contributors.sample.json └── contracts.json ├── .gitattributes ├── box-img-lg.png ├── box-img-sm.png ├── migrations └── 1_initial_migration.js ├── test ├── helpers │ ├── evmMine.js │ ├── initializeContracts.js │ ├── assertThrow.js │ ├── isVersioned.js │ ├── setContractsTest.js │ └── getParams.js └── VersionedTest.js ├── .solcover.js ├── .editorconfig ├── e2e ├── tsconfig.e2e.json ├── app.po.ts └── app.e2e-spec.ts ├── mocks ├── deploy-config.sample.json └── populate-poa-environment.sample.json ├── patch.js ├── scripts ├── full-node-private.sh ├── full-node.sh └── update-buildings.js ├── tsconfig.json ├── contracts ├── Migrations.sol ├── token │ └── ExperimentalToken.sol └── Versioned.sol ├── .travis.yml ├── protractor.conf.js ├── .gitignore ├── karma.conf.js ├── truffle.js └── CHANGELOG.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/barracks.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/portal.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/crystal_mine.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/gold_factory.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/gold_mine.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/gold_storage.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/crystal_factory.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/test/buildings/crystal_storage.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /src/app/+admin/admin.component.scss: -------------------------------------------------------------------------------- 1 | .admin-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/app/+trades/trades.component.scss: -------------------------------------------------------------------------------- 1 | .trades-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/app/+assets/+defense/defense.component.scss: -------------------------------------------------------------------------------- 1 | .defense-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/app/+assets/+units/units.component.scss: -------------------------------------------------------------------------------- 1 | .units-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/app/+assets/+research/research.component.scss: -------------------------------------------------------------------------------- 1 | .research-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/app/shared/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './abstract-container.component'; 2 | -------------------------------------------------------------------------------- /box-img-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/box-img-lg.png -------------------------------------------------------------------------------- /box-img-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/box-img-sm.png -------------------------------------------------------------------------------- /src/app/+assets/+buildings/buildings.component.scss: -------------------------------------------------------------------------------- 1 | .buildings-container { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'assets/e11-theme/theme'; 2 | 3 | @include e11-default-theme(); 4 | -------------------------------------------------------------------------------- /src/app/+trades/trades.component.html: -------------------------------------------------------------------------------- 1 |
2 | TRADES WORKING 3 |
4 | -------------------------------------------------------------------------------- /src/app/+assets/+defense/defense.component.html: -------------------------------------------------------------------------------- 1 |
2 | Defense working 3 |
4 | -------------------------------------------------------------------------------- /src/app/+assets/+research/research.component.html: -------------------------------------------------------------------------------- 1 |
2 | Research working 3 |
4 | -------------------------------------------------------------------------------- /src/assets/img/logo-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/logo-simple.png -------------------------------------------------------------------------------- /src/assets/img/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/logo-small.png -------------------------------------------------------------------------------- /data/preICO.json: -------------------------------------------------------------------------------- 1 | { 2 | "goal": 10, 3 | "cap": 13, 4 | "minPayment": 1, 5 | "maxPayment": 3, 6 | "rate": 1000 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_icon.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-icon() { 2 | .e11-icon { 3 | display: flex; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/img/e11-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/e11-logo-dark.png -------------------------------------------------------------------------------- /src/assets/img/metamask-e11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/metamask-e11.png -------------------------------------------------------------------------------- /src/assets/img/metamask-fox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/metamask-fox.png -------------------------------------------------------------------------------- /src/assets/img/metamask-lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/metamask-lock.png -------------------------------------------------------------------------------- /src/assets/img/metamask-oops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/metamask-oops.png -------------------------------------------------------------------------------- /src/assets/img/bg_resource_e11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/bg_resource_e11.png -------------------------------------------------------------------------------- /src/assets/img/bg_resource_gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/bg_resource_gold.png -------------------------------------------------------------------------------- /data/production/points.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "lowerPointsThreshold": 25, 4 | "upperPointsThreshold": 200 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/e11-theme/fonts/e11-font.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/e11-theme/fonts/e11-font.eot -------------------------------------------------------------------------------- /src/assets/e11-theme/fonts/e11-font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/e11-theme/fonts/e11-font.ttf -------------------------------------------------------------------------------- /src/assets/e11-theme/fonts/e11-font.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/e11-theme/fonts/e11-font.woff -------------------------------------------------------------------------------- /src/assets/img/bg_resource_crystal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/bg_resource_crystal.png -------------------------------------------------------------------------------- /src/assets/img/bg_resource_quantum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/bg_resource_quantum.png -------------------------------------------------------------------------------- /src/assets/img/units/thumbnails/archer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/units/thumbnails/archer.png -------------------------------------------------------------------------------- /src/assets/img/units/thumbnails/guardian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/units/thumbnails/guardian.png -------------------------------------------------------------------------------- /data/contributors.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "accounts": [ 3 | "0xe11e11e11e11e11e11e11e11e11e11e11e11e11e" 4 | ], 5 | "ether": 10, 6 | "e11": 2 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/barracks_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/barracks_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/barracks_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/barracks_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/barracks_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/barracks_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/portal_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/portal_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/portal_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/portal_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/portal_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/portal_3.png -------------------------------------------------------------------------------- /src/assets/img/units/thumbnails/tiny_warrior.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/units/thumbnails/tiny_warrior.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/experiment_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/experiment_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_mine_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_mine_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_mine_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_mine_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_mine_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_mine_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_mine_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_mine_4.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_mine_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_mine_5.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/city_center_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/city_center_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/city_center_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/city_center_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/city_center_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/city_center_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_mine_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_mine_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_mine_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_mine_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_mine_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_mine_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_mine_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_mine_4.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_mine_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_mine_5.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_factory_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_factory_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_factory_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_factory_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_factory_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_factory_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_factory_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_factory_4.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_factory_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_factory_5.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_storage_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_storage_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_storage_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_storage_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/gold_storage_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/gold_storage_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_factory_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_factory_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_factory_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_factory_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_factory_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_factory_3.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_factory_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_factory_4.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_factory_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_factory_5.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_storage_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_storage_1.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_storage_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_storage_2.png -------------------------------------------------------------------------------- /src/assets/img/buildings/thumbnails/crystal_storage_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e11-io/crypto-wars-solidity/HEAD/src/assets/img/buildings/thumbnails/crystal_storage_3.png -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require('./Migrations.sol'); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/+battle/+target/target.component.scss: -------------------------------------------------------------------------------- 1 | :host, .battle-target-container { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .battle-target-container { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /data/test/points.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "lowerPointsThreshold": 25, 4 | "upperPointsThreshold": 200 5 | }, 6 | "pointsToAdd": 100, 7 | "pointsToSubtract": 10 8 | } 9 | -------------------------------------------------------------------------------- /src/app/+battle/+history/history.component.scss: -------------------------------------------------------------------------------- 1 | :host, .battle-history-container { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .battle-history-container { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /data/test/battle.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "attackCooldown": 20, 4 | "rewardDefenderModifier": 15, 5 | "rewardAttackerModifier": 50, 6 | "revengeTimeThreshold": 400 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/production/battle.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "attackCooldown": 90, 4 | "rewardDefenderModifier": 15, 5 | "rewardAttackerModifier": 50, 6 | "revengeTimeThreshold": 4320 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/test/resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "initialResources": [ 3 | 4000, 4 | 4000, 5 | 1 6 | ], 7 | "initialResourcesNames": [ 8 | "gold", 9 | "crystal", 10 | "quantumDust" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/core/web3/transaction.model.ts: -------------------------------------------------------------------------------- 1 | export class Transaction { 2 | hash: string; 3 | callback: any; 4 | constructor(hash, callback){ 5 | this.hash = hash; 6 | this.callback = callback; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /data/production/resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "initialResources": [ 3 | 20000, 4 | 18000, 5 | 0 6 | ], 7 | "initialResourcesNames": [ 8 | "gold", 9 | "crystal", 10 | "quantumDust" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/core/player/army/player-army.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | 3 | export interface PlayerArmyState { 4 | } 5 | 6 | export const initialPlayerArmyState: PlayerArmyState = { 7 | }; 8 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | 7 | declare module "*.json" { 8 | const value: any; 9 | export default value; 10 | } 11 | -------------------------------------------------------------------------------- /test/helpers/evmMine.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | evmMine: async (blocksToSkip = 1) => { 3 | for (var i = 0; i < blocksToSkip; i++) { 4 | await web3.currentProvider.send({jsonrpc: "2.0", method: "evm_mine", params: [], id: 0}); 5 | } 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /src/app/shared/pipes/round.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({name: 'round'}) 4 | export class RoundPipe implements PipeTransform { 5 | 6 | transform (input:number) { 7 | return Math.floor(input); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/assets/e11-theme/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin setButtonBackground($baseColor) { 2 | background-color: $baseColor; 3 | &:hover { 4 | background-color: lighten($baseColor, 10%); 5 | } 6 | &:active { 7 | background-color: darken($baseColor, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-extras/village-extras.component.scss: -------------------------------------------------------------------------------- 1 | .village-extras-container { 2 | margin-top: 5rem; 3 | min-width: 19rem; 4 | 5 | .village-boosts, .village-alliance { 6 | height: 21rem; 7 | } 8 | .village-alliance { 9 | margin-top: 1.4rem; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/app/+onboarding/onboarding.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | flex: 1; 3 | display: flex; 4 | } 5 | 6 | .onboarding-container { 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | justify-content: center; 11 | flex: 1; 12 | overflow-y: auto; 13 | } 14 | -------------------------------------------------------------------------------- /src/core/shared/util/helpers.ts: -------------------------------------------------------------------------------- 1 | export const parseResource = function(type: number) { 2 | switch (type) { 3 | case 0: 4 | return 'gold' 5 | case 1: 6 | return 'crystal'; 7 | case 2: 8 | return 'quantum'; 9 | default: 10 | return null; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | copyPackages: [ 3 | 'openzeppelin-solidity', 4 | ], 5 | norpc: true, 6 | skipFiles: [ 7 | 'Migrations.sol', 8 | ], 9 | testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network coverage', 10 | }; 11 | -------------------------------------------------------------------------------- /src/core/player/assets/units/player-unit.model.ts: -------------------------------------------------------------------------------- 1 | export class PlayerUnit { 2 | id: number; 3 | index: number; 4 | quantity: number; 5 | 6 | constructor(data: any = {}) { 7 | this.id = data.id; 8 | this.index = data.index; 9 | this.quantity = data.quantity; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/core/player/resources/player-resources.model.ts: -------------------------------------------------------------------------------- 1 | export class PlayerResources { 2 | gold: number; 3 | crystal: number; 4 | quantum: number; 5 | constructor(data: any = {}) { 6 | this.gold = data.gold || 0; 7 | this.crystal = data.crystal || 0; 8 | this.quantum = data.quantum || 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/core/shared/util/type.ts: -------------------------------------------------------------------------------- 1 | const typeCache: { [label: string]: boolean } = {}; 2 | export function type(label: T | ''): T { 3 | if (typeCache[label]) { 4 | throw new Error(`Action type "${label}" is not unique"`); 5 | } 6 | 7 | typeCache[label] = true; 8 | 9 | return label; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/+assets/+defense/defense.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-defense', 5 | templateUrl: './defense.component.html', 6 | styleUrls: ['./defense.component.scss'] 7 | }) 8 | 9 | export class DefenseComponent { 10 | 11 | constructor() {} 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/+assets/assets.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-assets', 5 | templateUrl: './assets.component.html', 6 | styleUrls: ['./assets.component.scss'] 7 | }) 8 | 9 | export class AssetsComponent { 10 | 11 | constructor() { 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | browser.waitForAngularEnabled(false); 6 | browser.get('/'); 7 | return browser.driver.sleep(1000); 8 | } 9 | 10 | getHeader() { 11 | return element(by.css('h1')).getText(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/+assets/+research/research.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-research', 5 | templateUrl: './research.component.html', 6 | styleUrls: ['./research.component.scss'] 7 | }) 8 | 9 | export class ResearchComponent { 10 | 11 | constructor() {} 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/core/shared/status.model.ts: -------------------------------------------------------------------------------- 1 | export class Status { 2 | error: string; 3 | loading: boolean; 4 | 5 | constructor(data: any = initialStatus) { 6 | this.error = data.error; 7 | this.loading = data.loading; 8 | } 9 | 10 | } 11 | 12 | export const initialStatus: Status = { 13 | error: '', 14 | loading: false, 15 | }; 16 | -------------------------------------------------------------------------------- /src/app/+onboarding/onboarding.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /src/core/player/targets/player-target.model.ts: -------------------------------------------------------------------------------- 1 | import { VillageInfo } from "../village/village-info.model"; 2 | 3 | export class PlayerTarget extends VillageInfo { 4 | block: string; 5 | points: number; 6 | 7 | constructor(data: any = {}) { 8 | super(data); 9 | this.block = data.block; 10 | this.points = data.points; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/core/player/assets/buildings/player-building.model.ts: -------------------------------------------------------------------------------- 1 | export class PlayerBuilding { 2 | id: number; 3 | index: number; 4 | level: number; 5 | active: number; 6 | 7 | constructor(data: any = {}) { 8 | this.id = data.id; 9 | this.index = data.index; 10 | this.level = data.level; 11 | this.active = data.active; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/+dashboard/dashboard.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | flex: 1; 3 | overflow-y: auto; 4 | } 5 | .dashboard-container { 6 | display: flex; 7 | justify-content: center; 8 | padding: 3.3rem 8vw; 9 | flex-wrap: wrap; 10 | 11 | e11-village-logs, 12 | e11-village-extras { 13 | flex: 1; 14 | } 15 | .village-info { 16 | flex: 4; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-extras/village-extras.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-village-extras', 5 | templateUrl: './village-extras.component.html', 6 | styleUrls: ['./village-extras.component.scss'] 7 | }) 8 | 9 | export class VillageExtrasComponent { 10 | 11 | constructor() {} 12 | 13 | } 14 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('angular-truffle-box App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getHeader()).toContain('Angular Truffle Box'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /mocks/deploy-config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "mainnet" : { 3 | "privateKey": "e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e", 4 | "endpoint": "https://mainnet.infura.io/infura-api-key" 5 | }, 6 | "e11": { 7 | "privateKey": "e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e11e", 8 | "endpoint": "http://poa.e11.io:8311" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/app/shared/components/mobile-screen/mobile-screen.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |

{{'APPWIDE.MOBILE.title' | translate}}

7 |

8 | {{'APPWIDE.MOBILE.text' | translate}} 9 |

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/app/+admin/admin.module.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 2 | import { AdminComponent } from './admin.component'; 3 | 4 | @NgModule({ 5 | imports: [ 6 | ], 7 | declarations: [ 8 | AdminComponent 9 | ], 10 | exports: [ 11 | ], 12 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 13 | }) 14 | export class AdminModule { 15 | } 16 | -------------------------------------------------------------------------------- /src/core/assets/buildings/queue/queue-building.model.ts: -------------------------------------------------------------------------------- 1 | export class QueueBuilding { 2 | id: number; 3 | startBlock: number; 4 | endBlock: number; 5 | index: number; 6 | 7 | constructor(id: number, data: any = {}) { 8 | this.id = id; 9 | this.startBlock = data.startBlock; 10 | this.endBlock = data.endBlock; 11 | this.index = data.index; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/+onboarding/private-beta/private-beta.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-private-beta', 5 | templateUrl: './private-beta.component.html', 6 | styleUrls: ['../../shared/components/errors/errors.component.scss'] 7 | }) 8 | 9 | export class PrivateBetaComponent { 10 | 11 | constructor() { 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/+trades/trades.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | 4 | @Component({ 5 | selector: 'e11-assets', 6 | templateUrl: './trades.component.html', 7 | styleUrls: ['./trades.component.scss'] 8 | }) 9 | 10 | export class TradesComponent { 11 | 12 | constructor(private store: Store) { 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/+trades/trades.module.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; 2 | import { TradesComponent } from "./trades.component"; 3 | 4 | @NgModule({ 5 | imports: [ 6 | ], 7 | declarations: [ 8 | TradesComponent 9 | ], 10 | exports: [ 11 | ], 12 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 13 | }) 14 | export class TradesModule { 15 | } 16 | -------------------------------------------------------------------------------- /src/core/player/tokens/player-tokens.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | 3 | export interface PlayerTokensState { 4 | ethBalance: number; 5 | e11Balance: number; 6 | status: Status; 7 | } 8 | 9 | export const initialPlayerTokensState: PlayerTokensState = { 10 | ethBalance: 0, 11 | e11Balance: 0, 12 | status: initialStatus, 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/player/assets/units/player-units.state.ts: -------------------------------------------------------------------------------- 1 | import { PlayerUnit } from './player-unit.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface PlayerUnitsState { 5 | list: PlayerUnit[]; 6 | status: Status; 7 | } 8 | 9 | export const initialPlayerUnitsState: PlayerUnitsState = { 10 | list: [], 11 | status: initialStatus, 12 | }; 13 | -------------------------------------------------------------------------------- /src/core/assets/units/queue/queue-unit.model.ts: -------------------------------------------------------------------------------- 1 | export class QueueUnit { 2 | id: number; 3 | startBlock: number; 4 | endBlock: number; 5 | quantity: number; 6 | 7 | constructor(id: number, data: any = {}) { 8 | this.id = id; 9 | this.startBlock = data.startBlock; 10 | this.endBlock = data.endBlock; 11 | this.quantity = data.quantity; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/core/player/village/player-village.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | 3 | export interface PlayerVillageState { 4 | villageName: string; 5 | points: number; 6 | status: Status; 7 | } 8 | 9 | export const initialPlayerVillageState: PlayerVillageState = { 10 | villageName: '', 11 | points: 0, 12 | status: initialStatus, 13 | }; 14 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_progress-bar.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-progress-bar() { 2 | .e11-progress-bar { 3 | display: flex; 4 | height: .4rem; 5 | width: 100%; 6 | background: $color-border; 7 | border-radius: 10px; 8 | 9 | .bar { 10 | background: $color-primary; 11 | transition: width 1s ease-in-out; 12 | width: 0; 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "paths": { 8 | "contracts/*": [ 9 | "../build/contracts/*" 10 | ] 11 | }, 12 | "types": [ 13 | "node" 14 | ] 15 | }, 16 | "exclude": [ 17 | "test.ts", 18 | "**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/core/player/assets/buildings/player-buildings.state.ts: -------------------------------------------------------------------------------- 1 | import { PlayerBuilding } from './player-building.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface PlayerBuildingsState { 5 | list: PlayerBuilding[]; 6 | status: Status; 7 | } 8 | 9 | export const initialPlayerBuildingsState: PlayerBuildingsState = { 10 | list: [], 11 | status: initialStatus, 12 | }; 13 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts", 15 | "polyfills.ts" 16 | ], 17 | "include": [ 18 | "**/*.spec.ts", 19 | "**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/app/shared/components/mobile-screen/mobile-screen.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | changeDetection: ChangeDetectionStrategy.OnPush, 5 | selector: 'e11-mobile-screen', 6 | templateUrl: './mobile-screen.component.html', 7 | styleUrls: ['./mobile-screen.component.scss'] 8 | }) 9 | export class MobileScreenComponent { 10 | 11 | constructor() { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /patch.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const f = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js'; 3 | 4 | fs.readFile(f, 'utf8', function (err,data) { 5 | if (err) { 6 | return console.log(err); 7 | } 8 | var result = data.replace(/node: false/g, 'node: {crypto: true, stream: true}'); 9 | 10 | fs.writeFile(f, result, 'utf8', function (err) { 11 | if (err) return console.log(err); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/app/shared/components/loading/loading.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |

{{'APPWIDE.COMMON.loading' | translate}}

7 |

8 | {{'APPWIDE.TAKING-TO-LONG.text' | translate}}{{'APPWIDE.TAKING-TO-LONG.guide' | translate}} 9 |

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/core/assets/requirements/assets-requirements.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | 3 | export interface DataRequirementMap { 4 | [assetId: number]: number[]; 5 | } 6 | 7 | export interface AssetsRequirementsState { 8 | listMap: DataRequirementMap, 9 | status: Status, 10 | } 11 | 12 | export const initialAssetsRequirementsState: AssetsRequirementsState = { 13 | listMap: {}, 14 | status: initialStatus, 15 | }; 16 | -------------------------------------------------------------------------------- /src/core/assets/units/queue/units-queue.state.ts: -------------------------------------------------------------------------------- 1 | import { QueueUnit } from './queue-unit.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface AssetsUnitsQueueState { 5 | list: QueueUnit[], 6 | localList: QueueUnit[], 7 | status: Status, 8 | } 9 | 10 | export const initialAssetsUnitsQueueState: AssetsUnitsQueueState = { 11 | list: [], 12 | localList: [], 13 | status: initialStatus, 14 | }; 15 | -------------------------------------------------------------------------------- /src/core/player/army/player-army.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../shared/util/type'; 3 | 4 | export namespace PlayerArmyActions { 5 | 6 | export const Types = { 7 | SET_ARMY: type('[Player Army] Set Army'), 8 | } 9 | 10 | export class SetArmy implements Action { 11 | type = Types.SET_ARMY; 12 | 13 | constructor(public payload: any) { } 14 | } 15 | 16 | export type Actions 17 | = SetArmy 18 | } 19 | -------------------------------------------------------------------------------- /src/core/assets/units/data/units-data.state.ts: -------------------------------------------------------------------------------- 1 | import { DataUnit } from './data-unit.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface DataUnitMap { 5 | [unitId: string]: DataUnit; 6 | } 7 | export interface AssetsUnitsDataState { 8 | listMap: DataUnitMap, 9 | status: Status, 10 | } 11 | 12 | export const initialAssetsUnitsDataState: AssetsUnitsDataState = { 13 | listMap: {}, 14 | status: initialStatus, 15 | }; 16 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_avatar.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-avatar() { 2 | 3 | $avatar-default-size: 4rem; 4 | 5 | .e11-avatar { 6 | display: flex; 7 | justify-content: center; 8 | position: relative; 9 | width: 4rem; 10 | height: 4rem; 11 | background-position: center; 12 | background-size: cover; 13 | background-repeat: no-repeat; 14 | 15 | img { 16 | width: 100%; 17 | height: 100%; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/core/assets/buildings/queue/buildings-queue.state.ts: -------------------------------------------------------------------------------- 1 | import { QueueBuilding } from './queue-building.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface AssetsBuildingsQueueState { 5 | list: QueueBuilding[], 6 | localList: QueueBuilding[], 7 | status: Status, 8 | } 9 | 10 | export const initialAssetsBuildingsQueueState: AssetsBuildingsQueueState = { 11 | list: [], 12 | localList: [], 13 | status: initialStatus, 14 | }; 15 | -------------------------------------------------------------------------------- /scripts/full-node-private.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | curl https://e11.io/e11-private.json > e11-private.json 3 | geth --datadir=$HOME/.e11private init e11-private.json 4 | rm e11-private.json 5 | geth --networkid=311 --datadir=$HOME/.e11private --cache=512 --bootnodes enode://5ad3d840d39a91cbdf8082ded225c2b1ae62e2432aaa8e95c6a551713d6f0a497fe9129628d08a7ddb0adaf8fe9c129f3adc66abdb436c0587c061fd4962b212@54.201.158.240:30303 --rpc --rpcport 8311 --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcapi "bd,eth,net,web3,debug,personal" 6 | -------------------------------------------------------------------------------- /scripts/full-node.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | curl https://e11.io/genesis-311001.json > genesis-311001.json 3 | geth --datadir=$HOME/.e11-311001 init genesis-311001.json 4 | rm genesis-311001.json 5 | geth --networkid=311001 --datadir=$HOME/.e11-311001 --cache=512 --bootnodes=enode://64fe0a3ba632a7699714859eda5fd7fe331ce7ada82163f7d304494a5da2f3f36d8a63cc301fd5cd4b7f99619519ecd42ebd4e4f7b015823b2409b63ba5acbe0@34.217.128.7:30303 --rpc --rpcport 8311 --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcapi "bd,eth,net,web3,debug,personal" 6 | -------------------------------------------------------------------------------- /src/core/player/army/player-army.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerArmyState } from './player-army.state'; 2 | import { PlayerArmyActions } from './player-army.actions'; 3 | import { Status } from '../../shared/status.model'; 4 | 5 | export function playerArmyReducer (state = initialPlayerArmyState, action: PlayerArmyActions.Actions) { 6 | switch (action.type) { 7 | 8 | case PlayerArmyActions.Types.SET_ARMY: 9 | return action.payload; 10 | 11 | default: 12 | return state; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/core/assets/buildings/data/buildings-data.state.ts: -------------------------------------------------------------------------------- 1 | import { DataBuilding } from './data-building.model'; 2 | import { Status, initialStatus } from '../../../shared/status.model'; 3 | 4 | export interface DataBuildingMap { 5 | [buildingId: string]: DataBuilding; 6 | }; 7 | 8 | export interface AssetsBuildingsDataState { 9 | listMap: DataBuildingMap, 10 | status: Status, 11 | }; 12 | 13 | export const initialAssetsBuildingsDataState: AssetsBuildingsDataState = { 14 | listMap: {}, 15 | status: initialStatus, 16 | }; 17 | -------------------------------------------------------------------------------- /data/production/buildings/gold_mine.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 2, 3 | "name": "Gold mine", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 5000, 7 | "resource": 0, 8 | "blocks": 5, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 10, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": {}, 18 | "modifiers": { 19 | "price": "BV * (1.5 ** (BL-1))", 20 | "blocks": "BV * (1.5 ** (BL-1))", 21 | "goldRate": "BV * BL * (1.1**BL)" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data/production/buildings/portal.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 4, 3 | "name": "Portal", 4 | "maxLevel": 3, 5 | "baseStats": { 6 | "price": 32500, 7 | "resource": 2, 8 | "blocks": 12, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 0, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": { 18 | "1": ["city_center_3", "barracks_1"] 19 | }, 20 | "modifiers": { 21 | "price": "BV * (2.05 ** (BL-1))", 22 | "blocks": "BV * (2.05 ** (BL-1))" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /data/production/buildings/crystal_mine.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 3, 3 | "name": "Crystal Mine", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 6500, 7 | "resource": 1, 8 | "blocks": 8, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 0, 15 | "crystalRate": 9 16 | }, 17 | "levelsRequirements": {}, 18 | "modifiers": { 19 | "price": "BV * (1.65 ** (BL-1))", 20 | "blocks": "BV * (1.65 ** (BL-1))", 21 | "crystalRate": "BV * BL * (1.1**BL)" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data/production/buildings/gold_storage.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 7, 3 | "name": "Gold Storage", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 7500, 7 | "resource": 0, 8 | "blocks": 14, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 9500, 13 | "crystalCapacity": 0, 14 | "goldRate": 0, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": {}, 18 | "modifiers": { 19 | "price": "BV * (2 ** (BL-1))", 20 | "blocks": "BV * (2 ** (BL-1))", 21 | "goldCapacity": "BV * (1.8 * (Math.exp((20*BL/35))))" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "allowSyntheticDefaultImports": true, 11 | "paths": { 12 | "contracts/*": [ 13 | "../build/contracts/*" 14 | ] 15 | }, 16 | "target": "es5", 17 | "typeRoots": [ 18 | "node_modules/@types" 19 | ], 20 | "lib": [ 21 | "es2017", 22 | "dom" 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data/production/buildings/crystal_storage.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 8, 3 | "name": "Crystal Storage", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 9500, 7 | "resource": 1, 8 | "blocks": 21, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 8500, 14 | "goldRate": 0, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": {}, 18 | "modifiers": { 19 | "price": "BV * (2 ** (BL-1))", 20 | "blocks": "BV * (2 ** (BL-1))", 21 | "crystalCapacity": "BV * (1.8 * (Math.exp((20*BL/35))))" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/shared/components/loading/loading.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | changeDetection: ChangeDetectionStrategy.OnPush, 5 | selector: 'e11-loading', 6 | templateUrl: './loading.component.html', 7 | styleUrls: ['./loading.component.scss'] 8 | }) 9 | export class LoadingComponent { 10 | @Input() error: string; 11 | 12 | constructor() { 13 | 14 | } 15 | 16 | openGuide() { 17 | window.open('https://blog.e11.io/cryptowars-alpha-release-troubleshooting-guide-f4e21cd5c992', '_blank'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | constructor() public { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_input.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-input() { 2 | 3 | .e11-input { 4 | border: 0; 5 | background: transparent; 6 | border-bottom: 2px solid $color-border; 7 | font-size: 1.6rem; 8 | padding: 2px 0; 9 | color: $color-text-grey; 10 | font-family: $app-default-font-family; 11 | transition: border-color $app-default-animation; 12 | 13 | &:focus { 14 | outline: none; 15 | border-color: $color-primary; 16 | } 17 | &::placeholder { 18 | color: $color-text-grey; 19 | opacity: .5; 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /data/production/buildings/barracks.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 9, 3 | "name": "Barracks", 4 | "maxLevel": 5, 5 | "baseStats": { 6 | "price": 32500, 7 | "resource": 0, 8 | "blocks": 9, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 0, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": { 18 | "1": ["city_center_3"], 19 | "3": ["city_center_4"], 20 | "5": ["city_center_5"] 21 | }, 22 | "modifiers": { 23 | "price": "BV * (2.05 ** (BL-1))", 24 | "blocks": "BV * (2.05 ** (BL-1))" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /data/production/buildings/gold_factory.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 5, 3 | "name": "Gold Factory", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 55000, 7 | "resource": 0, 8 | "blocks": 33, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 54, 15 | "crystalRate": 0 16 | }, 17 | "levelsRequirements": { 18 | "1": ["city_center_3", "gold_mine_5"] 19 | }, 20 | "modifiers": { 21 | "price": "BV * (1.6 ** (BL-1))", 22 | "blocks": "BV * (1.6 ** (BL-1))", 23 | "goldRate": "BV * BL * ((1.06) ** BL)" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data/production/buildings/crystal_factory.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 6, 3 | "name": "Crystal Factory", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 100000, 7 | "resource": 1, 8 | "blocks": 45, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 0, 13 | "crystalCapacity": 0, 14 | "goldRate": 0, 15 | "crystalRate": 44 16 | }, 17 | "levelsRequirements": { 18 | "1": ["city_center_3", "crystal_mine_5"] 19 | }, 20 | "modifiers": { 21 | "price": "BV * (1.7 ** (BL-1))", 22 | "blocks": "BV * (1.7 ** (BL-1))", 23 | "crystalRate": "BV * BL * ((1.05) ** BL)" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data/production/buildings/city_center.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 1, 3 | "name": "City Center", 4 | "maxLevel": 10, 5 | "baseStats": { 6 | "price": 3500, 7 | "resource": 0, 8 | "blocks": 5, 9 | "health": 0, 10 | "defense": 0, 11 | "attack": 0, 12 | "goldCapacity": 15000, 13 | "crystalCapacity": 15000, 14 | "goldRate": 3, 15 | "crystalRate": 3 16 | }, 17 | "levelsRequirements": {}, 18 | "modifiers": { 19 | "price": "BV * (2.2**(BL-1))", 20 | "blocks": "BV * (2.2**(BL-1))", 21 | "goldCapacity": "BV * (1.6 * (Math.exp(20*BL/35)))", 22 | "crystalCapacity": "BV * (1.6 * (Math.exp(20*BL/35)))" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/core/web3/web3.state.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from './transaction.model'; 2 | import { Status, initialStatus } from '../shared/status.model'; 3 | 4 | export interface Web3State { 5 | accounts: string[]; 6 | activeAccount: string; 7 | bootstraped: boolean; 8 | lastBlock: number; 9 | loop: boolean; 10 | transactions: Transaction[]; 11 | status: Status; 12 | } 13 | 14 | export const initialWeb3State: Web3State = { 15 | accounts: [], 16 | activeAccount: null, 17 | bootstraped: false, 18 | lastBlock: 0, 19 | loop: false, 20 | transactions: [], 21 | status: initialStatus, 22 | } 23 | -------------------------------------------------------------------------------- /data/test/buildings/city_center.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeId": 1, 3 | "name": "City Center", 4 | "requirements": [], 5 | "price": 0, 6 | "resource": 0, 7 | "blocks": 1, 8 | "baseStats": { 9 | "health": 500, 10 | "defense": 50, 11 | "attack": 0, 12 | "goldCapacity": 1000, 13 | "crystalCapacity": 1000, 14 | "goldRate": 2, 15 | "crystalRate": 2 16 | }, 17 | "levels": [ 18 | { 19 | "requirements": [], 20 | "price": 3000, 21 | "resource": 0, 22 | "blocks": 30, 23 | "statsModifier": { 24 | "health": 500, 25 | "goldCapacity": 1000, 26 | "crystalCapacity": 1000 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/app/app.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../core/shared/util/type'; 3 | 4 | export namespace AppActions { 5 | 6 | export const Types = { 7 | SET_BUILDINGS: type('[App] Set Buildings'), 8 | SET_UNITS: type('[App] Set Units'), 9 | } 10 | 11 | export class SetBuildings implements Action { 12 | type = Types.SET_BUILDINGS; 13 | 14 | constructor(public payload: any) { } 15 | } 16 | 17 | 18 | export class SetUnits implements Action { 19 | type = Types.SET_UNITS; 20 | 21 | constructor(public payload: any) { } 22 | } 23 | 24 | 25 | export type Actions 26 | = SetBuildings 27 | | SetUnits 28 | } 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Angular Tests 2 | #language: node_js 3 | #node_js: 4 | #- "lts/*" 5 | #install: ./scripts/install-deps.sh 6 | #script: ./scripts/build.sh 7 | 8 | # Solidity tests 9 | sudo: required 10 | dist: trusty 11 | language: node_js 12 | node_js: 13 | - '8' 14 | cache: 15 | directories: 16 | - node_modules 17 | install: 18 | - npm install -g truffle 19 | - npm install -g ganache-cli 20 | - npm install 21 | env: 22 | global: 23 | - SOLIDITY_COVERAGE=true 24 | before_script: 25 | - truffle version 26 | script: 27 | - npm run test 28 | notifications: 29 | slack: e11io:jpVWDSReCf2l6mZlVI5RY68s 30 | on_success: change 31 | on_failure: always 32 | on_pull_requests: false 33 | -------------------------------------------------------------------------------- /src/app/shared/components/errors/errors.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | changeDetection: ChangeDetectionStrategy.OnPush, 5 | selector: 'e11-errors', 6 | templateUrl: './errors.component.html', 7 | styleUrls: ['./errors.component.scss'] 8 | }) 9 | export class ErrorsComponent { 10 | @Input() error: string; 11 | 12 | constructor() { 13 | 14 | } 15 | 16 | installMetamask() { 17 | window.open('https://metamask.io/', '_blank'); 18 | } 19 | 20 | openGuide() { 21 | window.open('https://blog.e11.io/cryptowars-alpha-release-troubleshooting-guide-f4e21cd5c992', '_blank'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/token/ExperimentalToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import 'openzeppelin-solidity/contracts/math/SafeMath.sol'; 4 | import 'openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol'; 5 | 6 | contract ExperimentalToken is StandardToken { 7 | 8 | string public constant name = "Experimental Token"; 9 | string public constant symbol = "e11"; 10 | 11 | uint8 public constant decimals = 18; 12 | 13 | uint256 public constant INITIAL_SUPPLY = 100000000 * 1 ether; 14 | 15 | /** 16 | * @dev Constructor that gives msg.sender all existing tokens. 17 | */ 18 | constructor() public { 19 | totalSupply_ = INITIAL_SUPPLY; 20 | balances[msg.sender] = INITIAL_SUPPLY; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/core/assets/units/data/data-unit.model.ts: -------------------------------------------------------------------------------- 1 | import { parseResource } from '../../../shared/util/helpers' 2 | 3 | export class DataUnit { 4 | 5 | id: number; 6 | name: string; 7 | health: number; 8 | defense: number; 9 | attack: number; 10 | price: number; 11 | resource: string; 12 | blocks: number; 13 | 14 | constructor(id: number, data: any = {}) { 15 | this.id = id; 16 | this.name = data[0]; 17 | this.health = data[1].toNumber(); 18 | this.defense = data[2].toNumber(); 19 | this.attack = data[3].toNumber(); 20 | this.price = data[4].toNumber(); 21 | this.resource = parseResource(data[5].toNumber()); 22 | this.blocks = data[6].toNumber(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/environments/environment.poa.ts: -------------------------------------------------------------------------------- 1 | const contracts = require('../../data/contracts.json'); 2 | 3 | export const environment = { 4 | blockTime: 10, 5 | production: false, 6 | remoteContracts: true, 7 | 8 | /* LATEST MIGRATION TO e11 311 */ 9 | contracts: { 10 | ExperimentalToken: contracts.ExperimentalToken, 11 | AssetsRequirements: contracts.AssetsRequirements, 12 | BuildingsData: contracts.BuildingsData, 13 | BuildingsQueue: contracts.BuildingsQueue, 14 | UserBuildings: contracts.UserBuildings, 15 | UserResources: contracts.UserResources, 16 | UserVault: contracts.UserVault, 17 | UserVillage: contracts.UserVillage, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | const contracts = require('../../data/contracts.json'); 2 | 3 | export const environment = { 4 | blockTime: 10, 5 | production: true, 6 | remoteContracts: true, 7 | 8 | /* LATEST MIGRATION TO e11 311 */ 9 | contracts: { 10 | ExperimentalToken: contracts.ExperimentalToken, 11 | AssetsRequirements: contracts.AssetsRequirements, 12 | BuildingsData: contracts.BuildingsData, 13 | BuildingsQueue: contracts.BuildingsQueue, 14 | UserBuildings: contracts.UserBuildings, 15 | UserResources: contracts.UserResources, 16 | UserVault: contracts.UserVault, 17 | UserVillage: contracts.UserVillage, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-queues/village-queues.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | .village-queues-container { 4 | display: flex; 5 | margin: 0 3rem; 6 | margin-top: 3rem; 7 | 8 | .e11-box-container { 9 | margin: 0 1.5rem; 10 | flex: 1; 11 | min-height: 29rem; 12 | 13 | &:first-child { 14 | margin-left: 0; 15 | } 16 | &:last-child { 17 | margin-right: 0; 18 | } 19 | 20 | .box-content { 21 | .price { 22 | opacity: 1; 23 | 24 | .bullet-outline { 25 | margin-left: 5px; 26 | margin-right: 3px; 27 | } 28 | } 29 | 30 | .empty-queue { 31 | cursor: pointer; 32 | } 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/shared/pipes/pipes.module.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 2 | 3 | import { BlockTimePipe } from './block-time.pipe'; 4 | import { PastBlockTimePipe } from './past-block-time.pipe'; 5 | import { LargeNumberPipe } from './large-number.pipe'; 6 | import { RoundPipe } from './round.pipe'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | ], 11 | declarations: [ 12 | BlockTimePipe, 13 | PastBlockTimePipe, 14 | LargeNumberPipe, 15 | RoundPipe 16 | ], 17 | exports: [ 18 | BlockTimePipe, 19 | PastBlockTimePipe, 20 | LargeNumberPipe, 21 | RoundPipe 22 | ], 23 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 24 | }) 25 | export class PipesModule { 26 | } 27 | -------------------------------------------------------------------------------- /mocks/populate-poa-environment.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "testAccounts": [ 3 | { 4 | "address": "0xe117a8d00e33988b88e7f22c1a9b25e9e0b1af5d", 5 | "privKey": "f366a1e9de5722f6743c87186988e2bedbce9a0825d5507a30b30253e2d56ad9", 6 | "buildings": ["3001","5002","5003","5005","5006","3007","3008","3009"], 7 | "resources": ["10000","10000","0"], 8 | "unitsIds": [1, 2, 3], 9 | "unitsQuantities": [10, 10, 10], 10 | "points": "500000", 11 | "username": "u-top-XX", 12 | "villagename": "v-top-XX", 13 | "attacks": [ 14 | { 15 | "to": "0xe117a8d00e33988b88e7f22c1a9b25e9e0b1af5b", 16 | "unitsIds": [1, 2, 3], 17 | "unitsQuantities": [5, 5, 5] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | v{{appVersion}} 5 |
6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/core/player/village/village-info.model.ts: -------------------------------------------------------------------------------- 1 | export class VillageInfo { 2 | address: string; 3 | username: string; 4 | villageName: string; 5 | unitsIds: number[]; 6 | unitsQuantities: number[]; 7 | battleStats: number[]; 8 | resources: number[]; 9 | canAttack: boolean; 10 | canTakeRevenge: boolean; 11 | 12 | constructor(data: any = {}) { 13 | this.address = data.address; 14 | this.username = data.username; 15 | this.villageName = data.villageName; 16 | this.unitsIds = data.unitsIds || []; 17 | this.unitsQuantities = data.unitsQuantities || []; 18 | this.battleStats = data.battleStats || []; 19 | this.resources = data.resources || []; 20 | this.canAttack = data.canAttack; 21 | this.canTakeRevenge = data.canTakeRevenge; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | blockTime: 10, 8 | production: false, 9 | remoteContracts: true, 10 | 11 | /* LATEST MIGRATION TO e11 311 */ 12 | contracts: { 13 | Migrations: null, 14 | ExperimentalToken: null, 15 | UserVault: null, 16 | UserResources: null, 17 | BuildingsData: null, 18 | UserBuildings: null, 19 | UserVillage: null, 20 | BuildingsQueue: null, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/app/+onboarding/onboarding.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { TranslateModule } from "@ngx-translate/core"; 5 | 6 | import { NewUserComponent } from './new-user/new-user.component'; 7 | import { OnboardingComponent } from './onboarding.component'; 8 | import { PrivateBetaComponent } from './private-beta/private-beta.component'; 9 | 10 | @NgModule({ 11 | imports: [ 12 | CommonModule, 13 | FormsModule, 14 | TranslateModule 15 | ], 16 | declarations: [ 17 | OnboardingComponent, 18 | NewUserComponent, 19 | PrivateBetaComponent 20 | ], 21 | exports: [ 22 | ], 23 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 24 | }) 25 | export class OnboardingModule { 26 | } 27 | -------------------------------------------------------------------------------- /src/core/player/targets/player-targets.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | import { PlayerTarget } from './player-target.model'; 3 | 4 | export interface PlayerTargetsState { 5 | expandedTarget: PlayerTarget; 6 | oldestBlock: number; 7 | currentBlock: number; 8 | targets: PlayerTarget[]; 9 | status: Status; 10 | searchThreshold: number; 11 | limitThreshold: number; 12 | targetsNonce: number; 13 | } 14 | 15 | export const initialPlayerTargetsState: PlayerTargetsState = { 16 | expandedTarget: null, 17 | oldestBlock: null, 18 | currentBlock: null, 19 | targets: [], 20 | status: initialStatus, 21 | searchThreshold: 10000, 22 | limitThreshold: 50000, 23 | targetsNonce: 0, 24 | }; 25 | -------------------------------------------------------------------------------- /test/helpers/initializeContracts.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | initializeContracts: async (contracts, fast = false) => { 3 | for (let instanceName in contracts) { 4 | if (contracts.hasOwnProperty(instanceName)) { 5 | let instance = contracts[instanceName]; 6 | for (let contractName in contracts) { 7 | if (contracts.hasOwnProperty(contractName)) { 8 | // Capitalize the contract name 9 | let capitalizedName = contractName.charAt(0).toUpperCase() + contractName.slice(1); 10 | if(instance[`set${capitalizedName}`]) { 11 | fast? instance[`set${capitalizedName}`](contracts[contractName].address): 12 | await instance[`set${capitalizedName}`](contracts[contractName].address); 13 | } 14 | } 15 | } 16 | } 17 | } 18 | 19 | return true; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/assets/e11-theme/theme.scss: -------------------------------------------------------------------------------- 1 | @import 'e11-font'; 2 | @import 'global'; 3 | @import 'mixins'; 4 | @import 'components/avatar'; 5 | @import 'components/badge'; 6 | @import 'components/box-container'; 7 | @import 'components/button'; 8 | @import 'components/catalog'; 9 | @import 'components/icon'; 10 | @import 'components/input'; 11 | @import 'components/progress-bar'; 12 | @import 'components/segments'; 13 | @import 'components/slider'; 14 | 15 | @mixin e11-default-theme() { 16 | .e11-default-theme { 17 | @include e11-avatar(); 18 | @include e11-badge(); 19 | @include e11-box-container(); 20 | @include e11-button(); 21 | @include e11-catalog(); 22 | @include e11-icon(); 23 | @include e11-input(); 24 | @include e11-progress-bar(); 25 | @include e11-segments(); 26 | @include e11-slider(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-extras/village-extras.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{ 'DASHBOARD.VILLAGE_EXTRAS.boosts' | translate }} 5 |
6 |
7 | 11 | {{ 'APPWIDE.coming-soon' | translate }} 12 |
13 |
14 | 15 |
16 |
17 | {{ 'DASHBOARD.VILLAGE_EXTRAS.alliance' | translate }} 18 |
19 |
20 | {{ 'APPWIDE.coming-soon' | translate }} 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /data/contracts.json: -------------------------------------------------------------------------------- 1 | { 2 | "AssetsRequirements": "0x3702a8d60570c1b7f4a060b62c8cd297b55f05dc", 3 | "BuildingsQueue": "0x6fa5c4d1e972bd7c749e91822ea30901a65f9e60", 4 | "UnitsData": "0x2b33efa121fdbfbdb9f7e2fdd2a16dfd35549960", 5 | "UserResources": "0xd76566edabfa8a269b02a470e4b44393ee46cbe4", 6 | "UserUnits": "0xdae4cde926f78a00eaae95cd203d3a3b96aa48c9", 7 | "BuildingsData": "0x03bdd78ed87c0426c436bedbac5cb65979e45ea1", 8 | "BattleSystem": "0x7be31a708ad424b75c159247f3525797e4ac9862", 9 | "UserBuildings": "0x965837103ecf4f0757ac7e9be77aec66ef2ff874", 10 | "ExperimentalToken": "0x63614401f234cbee2a56e11747539e4bd11aba11", 11 | "UnitsQueue": "0xc4b2c54d270a6b5c538db9dc4f6ba420b1f91092", 12 | "UserVillage": "0x8ddb8422d7c44a0ccaa104e623ceddc6eae90dd5", 13 | "UserVault": "0x6792b0fefe24d43d1610e80fb1f9f2e3fd075836", 14 | "PointsSystem": "0x6fd633b24ff5939896d81b06fa6f9f8729bad49d" 15 | } 16 | -------------------------------------------------------------------------------- /src/core/web3/web3.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { StoreModule } from '@ngrx/store'; 3 | import { EffectsModule } from '@ngrx/effects'; 4 | 5 | import { web3Reducer } from './web3.reducer'; 6 | import { initialWeb3State } from './web3.state'; 7 | import { Web3Effects } from './web3.effects'; 8 | import { Web3Service } from './web3.service'; 9 | 10 | 11 | @NgModule({ 12 | imports: [ 13 | StoreModule.forFeature('web3', web3Reducer, { 14 | initialState: initialWeb3State 15 | }), 16 | EffectsModule.forFeature([ 17 | Web3Effects, 18 | ]) 19 | ], 20 | providers: [ 21 | Web3Service 22 | ] 23 | }) 24 | export class Web3CoreModule { 25 | static forRoot(): ModuleWithProviders { 26 | return { 27 | ngModule: Web3CoreModule, 28 | providers: [ 29 | Web3Service 30 | ] 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/+battle/army-stats/army-stats.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{armyStats.attack | largeNumber}}

5 | 6 | 7 | {{'DATA.units.stats.dmg' | translate}} 8 | 9 |
10 |
11 |

{{armyStats.defense | largeNumber}}

12 | 13 | 14 | {{'DATA.units.stats.def' | translate}} 15 | 16 |
17 |
18 |

{{armyStats.hp | largeNumber}}

19 | 20 | 21 | {{'DATA.units.stats.hp' | translate}} 22 | 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_button.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-button() { 2 | 3 | $button-default-background: $color-primary; 4 | $button-default-color: $color-text; 5 | 6 | .e11-button { 7 | @extend .rounded; 8 | @extend .noselect; 9 | 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | color: $button-default-color; 14 | border: 0; 15 | font-size: 1.4rem; 16 | line-height: 2.1rem; 17 | font-weight: 500; 18 | padding: 8px 35px; 19 | transition: background $app-default-animation; 20 | cursor: pointer; 21 | 22 | &:focus { 23 | outline: none; 24 | } 25 | 26 | &.clear { 27 | @include setButtonBackground(transparent); 28 | border: 1px solid $color-primary; 29 | } 30 | 31 | @include setButtonBackground($button-default-background); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /data/production/units.json: -------------------------------------------------------------------------------- 1 | { 2 | "unitProperties":{ 3 | "id": 0, 4 | "name": "x", 5 | "stats": [ 6 | "health", "defense", "attack", 7 | "price", "resource", "blocks" 8 | ] 9 | }, 10 | "stats": { 11 | "health": 0, "defense": 1, "attack": 2, 12 | "price": 3, "resource": 4, "blocks": 5 13 | }, 14 | "initialUnits": [{ 15 | "id": 1, 16 | "name": "tiny_warrior", 17 | "requirements": [ 18 | 1009 19 | ], 20 | "stats": [ 21 | 120, 25, 120, 22 | 1000, 0, 3 23 | ] 24 | },{ 25 | "id": 2, 26 | "name": "archer", 27 | "requirements": [ 28 | 3009 29 | ], 30 | "stats": [ 31 | 80, 15, 250, 32 | 2000, 0, 4 33 | ] 34 | },{ 35 | "id": 3, 36 | "name": "guardian", 37 | "requirements": [ 38 | 5009 39 | ], 40 | "stats": [ 41 | 340, 175, 40, 42 | 6000, 0, 8 43 | ] 44 | }] 45 | } 46 | -------------------------------------------------------------------------------- /src/environments/environment.private.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=private` then `environment.private.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | blockTime: 1 * 3, // We multiply block time by 3 to avoid excessive calls to the node. 8 | production: false, 9 | remoteContracts: false, 10 | 11 | /* LATEST MIGRATION TO e11 311 */ 12 | contracts: { 13 | Migrations: null, 14 | ExperimentalToken: null, 15 | UserVault: null, 16 | UserResources: null, 17 | BuildingsData: null, 18 | UserBuildings: null, 19 | UserVillage: null, 20 | BuildingsQueue: null, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/app/+dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 5 | 6 |
7 | 13 | 14 | 17 | 18 |
19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /src/core/player/battle/player-battle.model.ts: -------------------------------------------------------------------------------- 1 | import { PlayerUnit } from '../assets/units/player-unit.model'; 2 | 3 | // TODO: Change PlayerUnit to UserUnit 4 | 5 | export class PlayerBattle { 6 | attacker: string; 7 | defender: string; 8 | 9 | attackerUnits: PlayerUnit[]; 10 | attackerDeadUnits: PlayerUnit[]; 11 | defenderUnits: PlayerUnit[]; 12 | defenderDeadUnits: PlayerUnit[]; 13 | 14 | attackerRewards: number[]; 15 | defenderRewards: number[]; 16 | 17 | constructor(data: any = {}) { 18 | this.attacker = data.attacker; 19 | this.defender = data.defender; 20 | 21 | this.attackerUnits = data.attackerUnits; 22 | this.attackerDeadUnits = data.attackerDeadUnits; 23 | 24 | this.defenderUnits = data.defenderUnits; 25 | this.defenderDeadUnits = data.defenderDeadUnits; 26 | 27 | this.attackerRewards = data.attackerRewards; 28 | this.defenderRewards = data.defenderRewards; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/+onboarding/new-user/new-user.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-new-user', 5 | templateUrl: './new-user.component.html', 6 | styleUrls: ['./new-user.component.scss'] 7 | }) 8 | 9 | export class NewUserComponent { 10 | private email: string; 11 | private username: string; 12 | private villageName: string; 13 | 14 | @Input() step: string = 'userCreation'; 15 | 16 | @Output() newApproveEmitter: EventEmitter = new EventEmitter(); 17 | @Output() newVillageEmitter: EventEmitter = new EventEmitter(); 18 | 19 | 20 | constructor() { 21 | 22 | } 23 | 24 | tryAgain() { 25 | this.step = 'userCreation'; 26 | } 27 | 28 | emitNewVillage() { 29 | let obj = {name: this.username, village: this.villageName, email: this.email}; 30 | 31 | this.newVillageEmitter.emit(obj); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/+onboarding/private-beta/private-beta.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | CryptoWars 4 | 5 |
6 |
7 | 8 |

{{'ONBOARDING.ERRORS.PRIVATE_ACCESS.title' | translate}}

9 |

10 | {{'ONBOARDING.ERRORS.PRIVATE_ACCESS.only-collaborators' | translate}} 11 |
12 | {{'ONBOARDING.ERRORS.PRIVATE_ACCESS.presale-info' | translate}} 13 |

14 | 15 | 18 | 19 |
20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /src/core/player/resources/player-resources.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | 3 | export interface PlayerResourcesRates { 4 | gold: number; 5 | crystal: number; 6 | }; 7 | 8 | export interface PlayerResourcesState { 9 | crystal: number; 10 | crystalCapacity: number; 11 | gold: number; 12 | goldCapacity: number; 13 | lockedCrystal: number; 14 | lockedGold: number; 15 | quantum: number; 16 | rates: PlayerResourcesRates; 17 | status: Status; 18 | }; 19 | 20 | export const initialPlayerResourcesState: PlayerResourcesState = { 21 | crystal: 0, 22 | crystalCapacity: 0, 23 | gold: 0, 24 | goldCapacity: 0, 25 | lockedCrystal: 0, 26 | lockedGold: 0, 27 | quantum: 0, 28 | rates: { 29 | gold: 0, 30 | crystal: 0, 31 | }, 32 | status: initialStatus, 33 | }; 34 | -------------------------------------------------------------------------------- /src/app/shared/pipes/large-number.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'largeNumber' 5 | }) 6 | export class LargeNumberPipe implements PipeTransform { 7 | 8 | transform(input: any, digits: number = 2, maxDigits: number = 3): any { 9 | var exp, rounded, 10 | suffixes = ['k', 'M', 'G', 'T', 'P', 'E']; 11 | 12 | if (Number.isNaN(input) || input == undefined) { 13 | return null; 14 | } 15 | 16 | if (input < 1000) { 17 | return input; 18 | } 19 | 20 | exp = Math.floor(Math.log(input) / Math.log(1000)); 21 | let number = parseFloat((input / Math.pow(1000, exp)).toFixed(digits)); 22 | let extraDigits = number.toString().replace('.','').length - maxDigits; 23 | if (extraDigits > 0) { 24 | return parseFloat(number.toFixed(digits - extraDigits)) + suffixes[exp - 1]; 25 | } 26 | return number + suffixes[exp - 1]; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome', 13 | chromeOptions: { 14 | args: [ "--headless", "--disable-gpu", "--window-size=800,600" ] 15 | } 16 | }, 17 | directConnect: true, 18 | baseUrl: 'http://localhost:4200/', 19 | framework: 'jasmine', 20 | jasmineNodeOpts: { 21 | showColors: true, 22 | defaultTimeoutInterval: 30000, 23 | print: function() {} 24 | }, 25 | onPrepare() { 26 | require('ts-node').register({ 27 | project: 'e2e/tsconfig.e2e.json' 28 | }); 29 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-logs/village-logs.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | .village-logs-container { 4 | margin-top: 5rem; 5 | min-width: 26rem; 6 | max-height: 43.4rem; 7 | min-height: 27.4rem; 8 | 9 | .box-content { 10 | &.empty { 11 | font-size: 1.6rem; 12 | } 13 | } 14 | 15 | .box-option { 16 | cursor: pointer; 17 | align-items: baseline; 18 | 19 | .message { 20 | font-size: 1.4rem; 21 | flex: 1; 22 | } 23 | .time { 24 | margin-left: .9rem; 25 | opacity: .7; 26 | } 27 | 28 | &.battle { 29 | .battle-resources { 30 | display: flex; 31 | width: 100%; 32 | white-space: nowrap; 33 | 34 | .resource { 35 | opacity: .85; 36 | margin-right: 1.5rem; 37 | .bullet-outline { 38 | margin-right: .5rem; 39 | } 40 | } 41 | } 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CryptoWars - e11.io 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/app/+battle/battle.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ 'BATTLE.your-army' | translate }}

4 | 5 | 6 |
7 |
8 |

9 | 10 | {{ 'BATTLE.select-target' | translate }} 11 | 12 |
13 | 14 | {{ 'BATTLE.battle-history' | translate }} 15 | 16 |
17 | 18 | 19 | {{ 'BATTLE.refresh-list' | translate }} 20 | 21 |

22 | 23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /src/app/+assets/assets.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{'ASSETS.TABS.buildings' | translate}} 5 |
6 |
7 | {{'ASSETS.TABS.offense' | translate}} 8 |
9 |
13 | {{'ASSETS.TABS.defense' | translate}} 14 |
15 |
19 | {{'ASSETS.TABS.research' | translate}} 20 |
21 |
22 | 23 | 24 | 25 |
26 | -------------------------------------------------------------------------------- /src/app/shared/components/mobile-screen/mobile-screen.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | .mobile-screen-container { 4 | flex: 1; 5 | padding: 1rem; 6 | display: none !important; 7 | flex-direction: column; 8 | position: fixed; 9 | width: 100%; 10 | height: 100%; 11 | top: 0; 12 | left: 0; 13 | z-index: 20; 14 | background-color: $color-dark; 15 | 16 | .e11-box-container { 17 | max-width: 45rem; 18 | flex-shrink: 0; 19 | text-align: center; 20 | margin: auto; 21 | 22 | .box-content { 23 | padding: 3rem 5.4rem 2rem 5.4rem; 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | 28 | .desc { 29 | margin: 2.5rem 0; 30 | text-align: center; 31 | color: $color-text-grey; 32 | font-size: 1.4rem; 33 | } 34 | } 35 | } 36 | } 37 | 38 | @media only screen and (max-width: 875px ) { 39 | .mobile-screen-container { 40 | display: flex !important; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/app/+assets/assets.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex: 1; 4 | overflow: hidden; 5 | } 6 | 7 | .assets-container { 8 | display: flex; 9 | flex: 1; 10 | flex-direction: column; 11 | overflow: hidden; 12 | 13 | .e11-segments { 14 | justify-content: center; 15 | margin-top: 3rem; 16 | } 17 | 18 | /deep/ { 19 | e11-buildings, 20 | e11-units { 21 | display: flex; 22 | flex: 1; 23 | overflow: hidden; 24 | } 25 | .buildings-container, 26 | .defense-container, 27 | .research-container, 28 | .units-container { 29 | display: flex; 30 | flex-direction: column; 31 | flex: 1; 32 | overflow: hidden; 33 | overflow-y: auto; 34 | margin-top: 1rem; 35 | padding: 0 13vw; 36 | } 37 | 38 | .e11-catalog { 39 | margin-top: 2rem; 40 | flex-shrink: 0; 41 | 42 | .item-unavailable { 43 | .title .name { 44 | font-weight: bold; 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/core/assets/units/data/units-data.reducer.ts: -------------------------------------------------------------------------------- 1 | import { AssetsUnitsDataActions } from './units-data.actions'; 2 | import { DataUnit } from './data-unit.model'; 3 | import { initialAssetsUnitsDataState } from './units-data.state'; 4 | import { Status } from '../../../shared/status.model'; 5 | 6 | export function assetsUnitsDataReducer (state = initialAssetsUnitsDataState, action: AssetsUnitsDataActions.Actions) { 7 | switch (action.type) { 8 | case AssetsUnitsDataActions.Types.GET_UNITS_DATA: 9 | return Object.assign({}, state, { 10 | status: new Status({ loading: true }) 11 | }) 12 | 13 | case AssetsUnitsDataActions.Types.GET_UNITS_DATA_SUCCESS: 14 | return Object.assign({}, state, { 15 | listMap: action.payload, 16 | status: new Status(), 17 | }); 18 | 19 | case AssetsUnitsDataActions.Types.GET_UNITS_DATA_FAILURE: 20 | return Object.assign({}, state, { 21 | status: new Status({ error: action.payload.error }), 22 | }); 23 | 24 | default: 25 | return state; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/+battle/army-selection/army-selection.component.scss: -------------------------------------------------------------------------------- 1 | .battle-army-selection-container { 2 | margin-top: 3rem; 3 | 4 | .e11-box-container { 5 | padding: 3rem; 6 | overflow: hidden; 7 | overflow-y: auto; 8 | } 9 | 10 | .unit { 11 | margin-bottom: 2.6rem; 12 | &:last-child { 13 | margin-bottom: 0; 14 | } 15 | 16 | .unit-info { 17 | display: flex; 18 | 19 | .e11-avatar { 20 | margin-right: .9rem; 21 | } 22 | .unit-data { 23 | display: flex; 24 | flex-direction: column; 25 | justify-content: center; 26 | color: #7F8CA3; 27 | 28 | .unit-qty { 29 | font-size: 1.4rem; 30 | font-weight: 300; 31 | color: white; 32 | strong { 33 | text-decoration: underline; 34 | font-weight: 500; 35 | margin-right: .4rem; 36 | font-size: 1.7rem; 37 | } 38 | } 39 | } 40 | } 41 | .unit-slider { 42 | margin-top: 2rem; 43 | } 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/core/assets/units/data/units-data.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../../shared/util/type'; 3 | 4 | export namespace AssetsUnitsDataActions { 5 | 6 | export const Types = { 7 | GET_UNITS_DATA: type('[Units Data] Get Units Data'), 8 | GET_UNITS_DATA_SUCCESS: type('[Units Data] Get Units Data Success'), 9 | GET_UNITS_DATA_FAILURE: type('[Units Data] Get Units Data Failure'), 10 | } 11 | 12 | export class GetUnitsData implements Action { 13 | type = Types.GET_UNITS_DATA; 14 | payload: any; 15 | 16 | constructor() { } 17 | } 18 | 19 | export class GetUnitsDataSuccess implements Action { 20 | type = Types.GET_UNITS_DATA_SUCCESS; 21 | 22 | constructor(public payload: any) { } 23 | } 24 | 25 | export class GetUnitsDataFailure implements Action { 26 | type = Types.GET_UNITS_DATA_FAILURE; 27 | 28 | constructor(public payload: any) { } 29 | } 30 | 31 | export type Actions 32 | = GetUnitsData 33 | | GetUnitsDataSuccess 34 | | GetUnitsDataFailure 35 | } 36 | -------------------------------------------------------------------------------- /src/core/player/assets/units/player-units.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerUnitsState } from './player-units.state'; 2 | import { PlayerUnit } from './player-unit.model'; 3 | import { PlayerUnitsActions } from './player-units.actions'; 4 | import { Status } from '../../../shared/status.model'; 5 | 6 | export function playerUnitsReducer (state = initialPlayerUnitsState, action: PlayerUnitsActions.Actions) { 7 | switch (action.type) { 8 | case PlayerUnitsActions.Types.GET_PLAYER_UNITS: 9 | return Object.assign({}, state, { 10 | status: new Status({ loading: true }), 11 | }) 12 | 13 | case PlayerUnitsActions.Types.GET_PLAYER_UNITS_SUCCESS: 14 | return Object.assign({}, state, { 15 | list: action.payload, 16 | status: new Status({ error: action.payload }), 17 | }); 18 | 19 | case PlayerUnitsActions.Types.GET_PLAYER_UNITS_FAILURE: 20 | return Object.assign({}, state, { 21 | status: new Status({ error: action.payload.status.error }), 22 | }); 23 | 24 | default: 25 | return state; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/core/assets/units/data/units-data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Observable } from 'rxjs'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | import { fromPromise } from 'rxjs/observable/fromPromise'; 7 | 8 | import { ContractsService } from '../../../shared/contracts.service'; 9 | import { Web3Service } from '../../../web3/web3.service'; 10 | 11 | @Injectable() 12 | export class AssetsUnitsDataService { 13 | 14 | constructor(private contractsService: ContractsService, 15 | private store: Store, 16 | private web3Service: Web3Service){ 17 | 18 | } 19 | 20 | getUnitsData() { 21 | return Observable.forkJoin( 22 | ['getAllUnitsA', 'getAllUnitsB'].map(functionName => 23 | this.web3Service.callContract( 24 | this.contractsService.UnitsDataInstance[functionName], 25 | [] 26 | ).then((result) => { 27 | return result; 28 | }) 29 | ) 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test/helpers/assertThrow.js: -------------------------------------------------------------------------------- 1 | function assertError(error, s, message) { 2 | assert.isAbove(error.message.search(s), -1, message); 3 | } 4 | 5 | async function assertThrows(block, message, errorCode) { 6 | try { 7 | await block() 8 | } catch (e) { 9 | return assertError(e, errorCode, message) 10 | } 11 | assert.fail('should have thrown before') 12 | } 13 | 14 | module.exports = { 15 | async assertJump(block, message = 'should have failed with invalid JUMP') { 16 | return assertThrows(block, message, 'invalid JUMP') 17 | }, 18 | 19 | async assertInvalidOpcode(block, message = 'should have failed with invalid opcode') { 20 | return assertThrows(block, message, 'invalid opcode') 21 | }, 22 | 23 | async assertRevert(block, message = 'should have failed with revert') { 24 | return assertThrows(block, message, 'revert') 25 | }, 26 | 27 | async assertSenderWithoutFunds(block, message = 'should have failed to send funds') { 28 | return assertThrows(block, message, 'sender doesn\'t have enough funds to send tx') 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/+dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { TranslateModule } from "@ngx-translate/core"; 4 | import { PipesModule } from '../shared/pipes/pipes.module'; 5 | 6 | import { DashboardComponent } from './dashboard.component'; 7 | 8 | import { VillageExtrasComponent } from './village-extras/village-extras.component'; 9 | import { VillageInfoComponent } from './village-info/village-info.component'; 10 | import { VillageLogsComponent } from './village-logs/village-logs.component'; 11 | import { VillageQueuesComponent } from './village-queues/village-queues.component'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | CommonModule, 16 | TranslateModule, 17 | PipesModule 18 | ], 19 | declarations: [ 20 | DashboardComponent, 21 | VillageExtrasComponent, 22 | VillageInfoComponent, 23 | VillageLogsComponent, 24 | VillageQueuesComponent 25 | ], 26 | exports: [], 27 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 28 | }) 29 | export class DashboardModule { 30 | } 31 | -------------------------------------------------------------------------------- /src/app/+assets/queue-navbar/queue-navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core'; 2 | import { Building } from '../../shared/models/building.model'; 3 | 4 | @Component({ 5 | selector: 'e11-queue-navbar', 6 | templateUrl: './queue-navbar.component.html', 7 | styleUrls: ['./queue-navbar.component.scss'] 8 | }) 9 | 10 | export class QueueNavbarComponent implements OnInit { 11 | @Input() disableCancel: boolean = false; 12 | @Input() remainingBlocks: number = 0; 13 | @Input() queueType: string; 14 | @Input() itemsInQueue: Building[] = []; 15 | 16 | @Output() itemClicked: EventEmitter = new EventEmitter(); 17 | 18 | private imagePathUrl: string = '/assets/img/'; 19 | 20 | constructor() { 21 | } 22 | 23 | ngOnInit() { 24 | this.imagePathUrl += this.queueType + '/thumbnails/'; 25 | } 26 | 27 | trackByFn(index, item) { 28 | return item.id; 29 | } 30 | 31 | onItemClick(item: any) { 32 | if (!item || !item.inProgress) { 33 | return; 34 | } 35 | this.itemClicked.emit(item); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/core/assets/requirements/assets-requirements.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Observable } from 'rxjs'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | 7 | import { ContractsService } from '../../shared/contracts.service'; 8 | import { Web3Service } from '../../web3/web3.service'; 9 | 10 | @Injectable() 11 | export class AssetsRequirementsService { 12 | 13 | constructor(private store: Store, 14 | private web3Service: Web3Service, 15 | private contractsService: ContractsService){ 16 | 17 | } 18 | 19 | getAssetsRequirements(ids: any[]) { 20 | // TODO Improve (must implement max amount of requirements) 21 | return Observable.forkJoin( 22 | ids.map(id => { 23 | return this.web3Service.callContract( 24 | this.contractsService.AssetsRequirementsInstance.getRequirements, 25 | [id] 26 | ).then((result) => { 27 | return result; 28 | }) 29 | }) 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/core/assets/buildings/data/buildings-data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Observable } from 'rxjs'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | import { fromPromise } from 'rxjs/observable/fromPromise'; 7 | 8 | import { ContractsService } from '../../../shared/contracts.service'; 9 | import { Web3Service } from '../../../web3/web3.service'; 10 | 11 | @Injectable() 12 | export class AssetsBuildingsDataService { 13 | 14 | constructor(private contractsService: ContractsService, 15 | private store: Store, 16 | private web3Service: Web3Service){ 17 | 18 | } 19 | 20 | getBuildingsData() { 21 | return Observable.forkJoin( 22 | ['getAllBuildingsA', 'getAllBuildingsB'].map(functionName => 23 | this.web3Service.callContract( 24 | this.contractsService.BuildingsDataInstance[functionName], 25 | [] 26 | ).then((result) => { 27 | return result; 28 | }) 29 | ) 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/core/assets/requirements/assets-requirements.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../shared/util/type'; 3 | 4 | export namespace AssetsRequirementsActions { 5 | 6 | export const Types = { 7 | GET_REQUIREMENTS: type('[Requirements] Get Requirements'), 8 | GET_REQUIREMENTS_SUCCESS: type('[Requirements] Get Requirements Success'), 9 | GET_REQUIREMENTS_FAILURE: type('[Requirements] Get Requirements Failure'), 10 | } 11 | 12 | export class GetRequirements implements Action { 13 | type = Types.GET_REQUIREMENTS; 14 | 15 | constructor(public payload: any) { } 16 | } 17 | 18 | export class GetRequirementsSuccess implements Action { 19 | type = Types.GET_REQUIREMENTS_SUCCESS; 20 | 21 | constructor(public payload: any) { } 22 | } 23 | 24 | export class GetRequirementsFailure implements Action { 25 | type = Types.GET_REQUIREMENTS_FAILURE; 26 | 27 | constructor(public payload: any) { } 28 | } 29 | 30 | 31 | export type Actions 32 | = GetRequirements 33 | | GetRequirementsSuccess 34 | | GetRequirementsFailure 35 | } 36 | -------------------------------------------------------------------------------- /src/core/assets/buildings/data/buildings-data.reducer.ts: -------------------------------------------------------------------------------- 1 | import { AssetsBuildingsDataActions } from './buildings-data.actions'; 2 | import { DataBuilding } from './data-building.model'; 3 | import { initialAssetsBuildingsDataState } from './buildings-data.state'; 4 | import { Status } from '../../../shared/status.model'; 5 | 6 | export function assetsBuildingsDataReducer (state = initialAssetsBuildingsDataState, action: AssetsBuildingsDataActions.Actions) { 7 | switch (action.type) { 8 | case AssetsBuildingsDataActions.Types.GET_BUILDINGS_DATA: 9 | return Object.assign({}, state, { 10 | status: new Status({ loading: true }), 11 | }) 12 | 13 | case AssetsBuildingsDataActions.Types.GET_BUILDINGS_DATA_SUCCESS: 14 | return Object.assign({}, state, { 15 | listMap: action.payload, 16 | status: new Status(), 17 | }); 18 | 19 | case AssetsBuildingsDataActions.Types.GET_BUILDINGS_DATA_FAILURE: 20 | return Object.assign({}, state, { 21 | status: new Status({ error: action.payload.error }), 22 | }); 23 | 24 | default: 25 | return state; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/core/player/assets/units/player-units.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../../shared/util/type'; 3 | 4 | export namespace PlayerUnitsActions { 5 | 6 | export const Types = { 7 | GET_PLAYER_UNITS: type('[Player Units] Get Player Units'), 8 | GET_PLAYER_UNITS_SUCCESS: type('[Player Units] Get Player Units Success'), 9 | GET_PLAYER_UNITS_FAILURE: type('[Player Units] Get Player Units Failure'), 10 | } 11 | 12 | export class GetPlayerUnits implements Action { 13 | type = Types.GET_PLAYER_UNITS; 14 | payload: any; 15 | constructor() { } 16 | } 17 | 18 | export class GetPlayerUnitsSuccess implements Action { 19 | type = Types.GET_PLAYER_UNITS_SUCCESS; 20 | 21 | constructor(public payload: any[]) { } 22 | } 23 | 24 | export class GetPlayerUnitsFailure implements Action { 25 | type = Types.GET_PLAYER_UNITS_FAILURE; 26 | 27 | constructor(public payload: any) { } 28 | } 29 | 30 | 31 | export type Actions 32 | = GetPlayerUnits 33 | | GetPlayerUnitsSuccess 34 | | GetPlayerUnitsFailure 35 | } 36 | -------------------------------------------------------------------------------- /src/app/shared/guards/bootstrap.guard.ts: -------------------------------------------------------------------------------- 1 | import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate } from "@angular/router"; 2 | import { Injectable } from "@angular/core"; 3 | import { Store } from '@ngrx/store'; 4 | import { Observable } from "rxjs/Observable"; 5 | 6 | import { CryptoWarsState } from "../../app.state"; 7 | import { environment } from '../../../environments/environment'; 8 | 9 | @Injectable() 10 | export class BootstrapGuard implements CanActivate { 11 | 12 | private bootstraped$: Observable; 13 | 14 | constructor(private store: Store) { 15 | this.bootstraped$ = this.store.select(s => s.web3.bootstraped); 16 | } 17 | 18 | canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { 19 | return new Promise((resolve) => { 20 | if (environment.production) { 21 | resolve(false); 22 | } 23 | let sub = this.bootstraped$.subscribe((bootstraped) => { 24 | if (bootstraped) { 25 | if (sub && sub.unsubscribe) sub.unsubscribe(); 26 | resolve(true); 27 | } 28 | }) 29 | }) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/app/shared/components/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; 2 | 3 | @Component({ 4 | changeDetection: ChangeDetectionStrategy.OnPush, 5 | selector: 'e11-navbar', 6 | templateUrl: './navbar.component.html', 7 | styleUrls: ['./navbar.component.scss'] 8 | }) 9 | export class NavbarComponent implements OnChanges { 10 | @Input() activeAccount: string; 11 | @Input() activeSection: any; 12 | @Input() balance: any; 13 | @Input() childNavDisabled: boolean = false; 14 | @Input() ethBalance: any; 15 | @Input() points: number; 16 | @Input() playerResources: any; 17 | 18 | blockiesOptions: any = {size: 8, scale: 6}; 19 | constructor() { 20 | 21 | } 22 | 23 | ngOnChanges(changes: SimpleChanges) { 24 | if(changes.activeAccount && changes.activeAccount.currentValue !== changes.activeAccount.previousValue) { 25 | this.activeAccount = changes.activeAccount.currentValue; 26 | this.blockiesOptions = Object.assign({}, this.blockiesOptions, {seed: this.activeAccount.toLowerCase()}); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/core/assets/buildings/data/buildings-data.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../../shared/util/type'; 3 | 4 | export namespace AssetsBuildingsDataActions { 5 | 6 | export const Types = { 7 | GET_BUILDINGS_DATA: type('[Buildings Data] Get Buildings Data'), 8 | GET_BUILDINGS_DATA_SUCCESS: type('[Buildings Data] Get Buildings Data Success'), 9 | GET_BUILDINGS_DATA_FAILURE: type('[Buildings Data] Get Buildings Data Failure'), 10 | } 11 | 12 | export class GetBuildingsData implements Action { 13 | type = Types.GET_BUILDINGS_DATA; 14 | payload; 15 | 16 | constructor() { } 17 | } 18 | 19 | export class GetBuildingsDataSuccess implements Action { 20 | type = Types.GET_BUILDINGS_DATA_SUCCESS; 21 | 22 | constructor(public payload: any) { } 23 | } 24 | 25 | export class GetBuildingsDataFailure implements Action { 26 | type = Types.GET_BUILDINGS_DATA_FAILURE; 27 | 28 | constructor(public payload: any) { } 29 | } 30 | 31 | export type Actions 32 | = GetBuildingsData 33 | | GetBuildingsDataSuccess 34 | | GetBuildingsDataFailure 35 | } 36 | -------------------------------------------------------------------------------- /src/core/assets/requirements/assets-requirements.reducer.ts: -------------------------------------------------------------------------------- 1 | import { AssetsRequirementsActions } from './assets-requirements.actions'; 2 | import { DataRequirementMap, initialAssetsRequirementsState } from './assets-requirements.state'; 3 | import { Status } from '../../shared/status.model'; 4 | 5 | 6 | export function assetsRequirementsReducer (state = initialAssetsRequirementsState, action: AssetsRequirementsActions.Actions) { 7 | switch (action.type) { 8 | 9 | case AssetsRequirementsActions.Types.GET_REQUIREMENTS: 10 | return Object.assign({}, state, { 11 | status: new Status({ loading: true }) 12 | }) 13 | 14 | case AssetsRequirementsActions.Types.GET_REQUIREMENTS_SUCCESS: 15 | let requirementsMap: DataRequirementMap = Object.assign({}, state.listMap); 16 | action.payload.ids.forEach((id, i) => { 17 | requirementsMap[id] = action.payload.requirements[i].map(r => r.toNumber()); 18 | }) 19 | return Object.assign({}, state, { 20 | listMap: requirementsMap, 21 | status: new Status({loading: false}) 22 | }) 23 | 24 | default: 25 | return state; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/core/player/battle/player-battle.state.ts: -------------------------------------------------------------------------------- 1 | import { Status, initialStatus } from '../../shared/status.model'; 2 | import { PlayerBattle } from './player-battle.model'; 3 | import { BattleDetail } from './battle-detail.model'; 4 | 5 | export interface PlayerBattleState { 6 | expandedBattleDetail: string; 7 | attackCooldown: number; 8 | lastAttackBlock: number; 9 | rewardAttackerModifier: number; 10 | rewardDefenderModifier: number; 11 | status: Status; 12 | oldestBlock: number; 13 | currentBlock: number; 14 | battles: BattleDetail[]; 15 | searchThreshold: number; 16 | limitThreshold: number; 17 | } 18 | 19 | export const initialPlayerBattleState: PlayerBattleState = { 20 | expandedBattleDetail: null, 21 | attackCooldown: 0, 22 | lastAttackBlock: 0, 23 | rewardAttackerModifier: 0, 24 | rewardDefenderModifier: 0, 25 | status: initialStatus, 26 | oldestBlock: null, 27 | currentBlock: null, 28 | battles: [], 29 | searchThreshold: 10000, 30 | limitThreshold: 50000, 31 | }; 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /libpeerconnection.log 31 | npm-debug.log 32 | .node-xmlhttprequest* 33 | testem.log 34 | /typings 35 | /testFalse 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | 45 | # Solidity Contracts Builds 46 | /build 47 | 48 | # Doxity scripts 49 | /scripts/doxity* 50 | 51 | # Coverage 52 | /coverage 53 | /coverageEnv 54 | scTopics 55 | allFiredEvents 56 | 57 | # ETH 58 | e11.json 59 | signer.json 60 | signer.pass 61 | .datadir 62 | 63 | # Scripts 64 | /data/contributors.json 65 | 66 | # Mocks 67 | /mocks/deploy-config.json 68 | /mocks/populate-poa-environment.json 69 | 70 | # Coveralls 71 | .coveralls.yml 72 | -------------------------------------------------------------------------------- /src/app/+battle/army-stats/army-stats.component.scss: -------------------------------------------------------------------------------- 1 | .battle-army-stats-container { 2 | .e11-box-container { 3 | padding: 2.4rem 1rem; 4 | } 5 | .army-stats { 6 | display: flex; 7 | flex-direction: row; 8 | margin-top: 1.5rem; 9 | .stat { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | justify-content: center; 14 | flex: 1; 15 | position: relative; 16 | 17 | &:not(:first-child):not(:last-child) { 18 | &::before, 19 | &::after { 20 | content: ''; 21 | position: absolute; 22 | width: 1px; 23 | height: 3rem; 24 | background: #313D4F; 25 | } 26 | &::after { 27 | right: 0; 28 | } 29 | &::before { 30 | left: 0; 31 | } 32 | } 33 | 34 | span { 35 | display: flex; 36 | align-items: center; 37 | text-transform: uppercase; 38 | font-size: 1rem; 39 | line-height: 1; 40 | margin-top: .5rem; 41 | .e11-icon { 42 | margin-right: .3rem; 43 | font-size: 1.1rem; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app/shared/components/loading/loading.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | :host { 4 | display: flex; 5 | align-items: center; 6 | flex-direction: column; 7 | justify-content: center; 8 | flex: 1; 9 | } 10 | 11 | .loading-container { 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | padding-top: 10vh; 16 | 17 | .logo-simple { 18 | width: 48rem; 19 | max-width: $app-errors-container-max-width; 20 | margin-bottom: 7rem; 21 | } 22 | 23 | .e11-box-container { 24 | width: 45rem; 25 | flex-shrink: 0; 26 | max-width: $app-errors-container-max-width * 2; 27 | margin-bottom: 10vh; 28 | 29 | .box-content { 30 | padding: 3rem 5.4rem 2rem 5.4rem; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | 35 | .desc { 36 | margin: 2.5rem 0; 37 | text-align: center; 38 | color: $color-text-grey; 39 | font-size: 1.4rem; 40 | .underlined { 41 | font-size: 1.4rem; 42 | text-decoration: underline; 43 | cursor: pointer; 44 | } 45 | } 46 | 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/app/+battle/army-selection/army-selection.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
8 |
9 |
10 | 11 | {{unitsToBattle[unit.id] | largeNumber}}/{{unit.quantity | largeNumber}} 12 | 13 | 14 | {{'DATA.units.' + [unit.name] + '.name' | translate}} 15 | 16 |
17 |
18 |
20 | 26 |
27 |
28 | 29 |
30 |
31 | -------------------------------------------------------------------------------- /src/app/shared/components/errors/errors.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | :host { 4 | display: flex; 5 | align-items: center; 6 | flex-direction: column; 7 | justify-content: center; 8 | flex: 1; 9 | } 10 | 11 | .errors-container { 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | padding-top: 10vh; 16 | 17 | .logo-simple { 18 | width: 48rem; 19 | max-width: $app-errors-container-max-width; 20 | margin-bottom: 7rem; 21 | } 22 | 23 | .e11-box-container { 24 | width: 45rem; 25 | flex-shrink: 0; 26 | max-width: $app-errors-container-max-width * 2; 27 | margin-bottom: 10vh; 28 | 29 | .box-content { 30 | padding: 4rem 5.4rem; 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | 35 | .metamask-logo { 36 | height: 10rem; 37 | margin-bottom: 3rem; 38 | } 39 | 40 | .metamask-desc { 41 | margin: 3rem 0; 42 | text-align: center; 43 | color: $color-text-grey; 44 | font-size: 1.4rem; 45 | } 46 | 47 | .e11-button { 48 | width: 100%; 49 | } 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /src/assets/e11-theme/_variables.scss: -------------------------------------------------------------------------------- 1 | $app-default-radius: 4px; 2 | $app-default-animation: .2s ease-in-out; 3 | $app-default-font-family: "Roboto", sans-serif; 4 | $app-errors-container-max-width: 23vw; 5 | 6 | $color-text: #FFFFFF; 7 | $color-text-grey: #7F8FA4; 8 | $color-border: #313D4F; 9 | 10 | $color-dark: #1B2431; 11 | $color-dark-alt: #222C3C; 12 | 13 | $color-light: #6C7992; 14 | $color-light-alt: #273142; 15 | 16 | $color-contrast: #20547F; 17 | $color-contrast-light: #1A91EB; 18 | 19 | $color-primary: #1991EB; 20 | $color-primary-alt: #1682D3; 21 | 22 | $color-resource-e11: #2D6FA8; 23 | $color-resource-quantum: #9013FE; 24 | $color-resource-crystal: #2AB5D6; 25 | $color-resource-gold: #D9CA2B; 26 | 27 | $color-warning: #DA932C; 28 | $color-error: #D35847; 29 | $color-success: #66B92E; 30 | 31 | $color-hp: #39B54A; 32 | $color-dmg: #D35847; 33 | $color-def: #2BB8D9; 34 | 35 | $colors: ( 36 | e11: $color-resource-e11, 37 | quantum: $color-resource-quantum, 38 | crystal: $color-resource-crystal, 39 | gold: $color-resource-gold, 40 | 41 | warning: $color-warning, 42 | error: $color-error, 43 | success: $color-success, 44 | 45 | hp: $color-hp, 46 | dmg: $color-dmg, 47 | def: $color-def 48 | ); 49 | -------------------------------------------------------------------------------- /src/redirect-cryptowars-jp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | Redirect to cryptowars.jp 11 | 12 | 31 | 32 |

33 | If you are not redirected automatically, follow this link to cryptowars.jp. 34 |

35 | 36 | 37 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-logs/village-logs.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, EventEmitter, Output } from '@angular/core'; 2 | import { Router } from "@angular/router"; 3 | import { Store } from '@ngrx/store'; 4 | import { BattleDetail } from '../../../core/player/battle/battle-detail.model'; 5 | import { PlayerBattleActions } from '../../../core/player/battle/player-battle.actions'; 6 | 7 | import { getCurrentBlockFromStore } from '../../shared/util/helpers'; 8 | 9 | @Component({ 10 | selector: 'e11-village-logs', 11 | templateUrl: './village-logs.component.html', 12 | styleUrls: ['./village-logs.component.scss'] 13 | }) 14 | 15 | export class VillageLogsComponent { 16 | 17 | @Input() battleDetails: BattleDetail[] = []; 18 | @Output() logClicked: EventEmitter = new EventEmitter(); 19 | 20 | currentBlock: number; 21 | resources: string[] = ['gold', 'crystal', 'quantum']; 22 | 23 | constructor(public store: Store, 24 | private router: Router) { 25 | this.currentBlock = getCurrentBlockFromStore(this.store); 26 | } 27 | 28 | trackByFn(index, battleDetail) { 29 | return battleDetail.village.address; 30 | } 31 | 32 | log(selectedBattle: BattleDetail) { 33 | this.logClicked.emit(selectedBattle); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/redirect-alpha-cryptowars-jp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | Redirect to alpha.cryptowars.jp 11 | 12 | 31 | 32 |

33 | If you are not redirected automatically, follow this link to alpha.cryptowars.jp. 34 |

35 | 36 | 37 | -------------------------------------------------------------------------------- /src/app/+assets/assets.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { RouterModule } from "@angular/router"; 5 | import { TranslateModule } from "@ngx-translate/core"; 6 | 7 | import { AssetsComponent } from './assets.component'; 8 | import { BuildingsComponent } from './+buildings/buildings.component'; 9 | import { DefenseComponent } from './+defense/defense.component'; 10 | import { QueueNavbarComponent } from './queue-navbar/queue-navbar.component'; 11 | import { ResearchComponent } from './+research/research.component'; 12 | import { UnitsComponent } from './+units/units.component'; 13 | 14 | import { PipesModule } from '../shared/pipes/pipes.module'; 15 | 16 | @NgModule({ 17 | imports: [ 18 | CommonModule, 19 | FormsModule, 20 | RouterModule, 21 | TranslateModule, 22 | PipesModule 23 | ], 24 | declarations: [ 25 | AssetsComponent, 26 | BuildingsComponent, 27 | DefenseComponent, 28 | QueueNavbarComponent, 29 | ResearchComponent, 30 | UnitsComponent, 31 | ], 32 | exports: [ 33 | ], 34 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 35 | }) 36 | export class AssetsModule { 37 | } 38 | -------------------------------------------------------------------------------- /src/core/shared/util/get-web3.ts: -------------------------------------------------------------------------------- 1 | import Web3 from 'web3'; 2 | 3 | let getWeb3 = new Promise((resolve, reject) => { 4 | // Wait for loading completion to avoid race conditions with web3 injection timing. 5 | window.addEventListener('load', () => { 6 | var results; 7 | var web3 = window['web3']; 8 | 9 | // Checking if Web3 has been injected by the browser (Mist/MetaMask) 10 | if (typeof web3 !== 'undefined') { 11 | // Use Mist/MetaMask's provider.; 12 | web3 = new Web3(web3.currentProvider); 13 | 14 | results = { 15 | web3: web3 16 | }; 17 | 18 | console.log('Injected web3 detected.'); 19 | 20 | resolve(results); 21 | } else { 22 | // TODO Remove force direct web3 provider 23 | resolve('no_web3_provider'); 24 | /* 25 | // Fallback to localhost if no web3 injection. 26 | // We've configured this to use the development console's port by default. 27 | var provider = new Web3.providers.HttpProvider('http://localhost:9545'); 28 | 29 | web3 = new Web3(provider); 30 | 31 | results = { 32 | web3: web3 33 | }; 34 | 35 | console.log('No web3 instance injected, using Local web3.'); 36 | 37 | resolve(results); 38 | */ 39 | } 40 | }) 41 | }) 42 | 43 | export default getWeb3; 44 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-info/village-info.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { PlayerResourcesState } from '../../../core/player/resources/player-resources.state'; 5 | 6 | import { Building } from '../../shared/models/building.model'; 7 | import { UnitMap } from '../../shared/models/unit.model'; 8 | 9 | @Component({ 10 | selector: 'e11-village-info', 11 | templateUrl: './village-info.component.html', 12 | styleUrls: ['./village-info.component.scss'] 13 | }) 14 | 15 | export class VillageInfoComponent implements OnChanges { 16 | @Input() unitsMap: UnitMap = {}; 17 | @Input() playerResources: PlayerResourcesState; 18 | @Input() ownedBuildings: Building[] = []; 19 | @Input() playerBalance: number; 20 | @Input() villageName: string; 21 | 22 | @Output() navigateTo: EventEmitter = new EventEmitter(); 23 | 24 | 25 | unitsQuantity: number = 0; 26 | 27 | constructor(private router: Router) {} 28 | 29 | 30 | ngOnChanges(changes: SimpleChanges) { 31 | if (changes.unitsMap) { 32 | this.unitsQuantity = 0; 33 | Object.values(this.unitsMap).forEach(unit => { 34 | this.unitsQuantity += unit.quantity; 35 | }) 36 | } 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /test/helpers/isVersioned.js: -------------------------------------------------------------------------------- 1 | const { assertRevert } = require('./assertThrow'); 2 | const ExperimentalToken = artifacts.require('ExperimentalToken'); 3 | 4 | module.exports = { 5 | isVersioned: async (instance, contract) => { 6 | // Get contract name 7 | let contractName = contract._json.contractName; 8 | if (!contractName) return; 9 | 10 | // Checks if contract has is'ContractName' identifier function. 11 | let isContract = await instance[`is${contractName}`](); 12 | if (!isContract) return; 13 | 14 | // Checks if contract's version is 0 15 | let version = await instance.version(); 16 | if (version != 0) return; 17 | 18 | // Checks if contract is upgradeable 19 | let newInstance = await contract.new(); 20 | await newInstance[`set${contractName}Version`](instance.address, 1); 21 | 22 | // Check if contract is not upgradeable to another contract type 23 | let basicToken = await ExperimentalToken.new(); 24 | await assertRevert(async () => { 25 | await instance[`set${contractName}Version`](basicToken.address, 1); 26 | }); 27 | 28 | // Checks if contract fails when upgraded from equal or higher version 29 | await assertRevert(async () => { 30 | await instance[`set${contractName}Version`](newInstance.address, 1); 31 | }); 32 | 33 | return true; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/app/shared/components/abstract-container.component.ts: -------------------------------------------------------------------------------- 1 | import { OnDestroy } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Subscription } from 'rxjs/Subscription'; 4 | import { Observable } from 'rxjs/Observable'; 5 | 6 | import { CryptoWarsState, AppState } from '../../app.state'; 7 | 8 | export abstract class AbstractContainerComponent implements OnDestroy { 9 | 10 | private subs: Subscription[] = []; 11 | 12 | app$: Observable; 13 | activeAccount: string = ''; 14 | 15 | constructor(protected store: Store) { 16 | this.app$ = this.store.select(s => s.app).filter(app => app.initialized); 17 | this.addToSubscriptions( 18 | this.setActiveAccount() 19 | ); 20 | } 21 | 22 | setActiveAccount() { 23 | return this.store.select('web3').subscribe(web3 => { 24 | this.activeAccount = web3.activeAccount; 25 | }) 26 | } 27 | 28 | protected addToSubscriptions(...subs) { 29 | subs.forEach(sub => { 30 | if (!(sub instanceof Subscription)) { 31 | console.log(sub); 32 | throw new Error('Invalid subscription, object should be of type Subscription'); 33 | } 34 | this.subs.push(sub); 35 | }); 36 | } 37 | 38 | ngOnDestroy() { 39 | this.subs.forEach(sub => { 40 | sub.unsubscribe(); 41 | }); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/app/+battle/+history/history.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | {{ 'BATTLE.LOADING.battles' | translate }} 7 | 8 | 9 | {{ 'BATTLE.HISTORY.not-found' | translate }} 10 | 11 |
12 | 13 | 14 | 19 | 20 | 21 |
22 |
23 | 24 | {{ 'BATTLE.HISTORY.find-more' | translate }} 25 | 26 | 27 | {{ 'BATTLE.LOADING.more-history' | translate }} 28 | 29 |
30 |
31 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /src/app/shared/pipes/block-time.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { environment } from '../../../environments/environment'; 3 | 4 | @Pipe({ 5 | name: 'blockTime' 6 | }) 7 | export class BlockTimePipe implements PipeTransform { 8 | 9 | transform(blocks: any, args?: any): any { 10 | if (!blocks) { 11 | blocks = 0; 12 | if (args == 'hh') { 13 | return '(00:00)'; 14 | } else { 15 | return '0s'; 16 | } 17 | } 18 | 19 | let blockSeconds = blocks * environment.blockTime; 20 | let time = new Date(blockSeconds * 1000); 21 | 22 | if (args == 'hh') { 23 | return time.toISOString().substr(11, 8); 24 | } else { 25 | let months = Number(time.toISOString().substr(5, 2)) - 1; 26 | let days = Number(time.toISOString().substr(8, 2)) - 1; 27 | let hours = Number(time.toISOString().substr(11, 2)); 28 | let minutes = Number(time.toISOString().substr(14, 2)); 29 | let seconds = Number(time.toISOString().substr(17, 2)); 30 | 31 | return (months ? months + 'm' : '') + 32 | (days ? days + 'd' : '') + 33 | (!months && hours ? hours + 'h' : '') + 34 | (!months && !days && minutes ? minutes + 'm' : '') + 35 | (!months && !days && !hours && seconds ? seconds + 's' : ''); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /contracts/Versioned.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | import 'openzeppelin-solidity/contracts/ownership/Ownable.sol'; 3 | 4 | /** 5 | * @title Versioned 6 | * @dev The Versioned contract has a version number, and provides migration functionality. 7 | */ 8 | contract Versioned is Ownable { 9 | uint public version; 10 | mapping(address => bool) public migratedUsers; 11 | 12 | event UserMigrated(address indexed user, address indexed newContract); 13 | 14 | /** 15 | * @dev The Versioned constructor, unused 16 | constructor() public { 17 | } 18 | */ 19 | 20 | /** 21 | * @dev Throws if called by a migrated user. 22 | */ 23 | modifier notMigrated() { 24 | require(migratedUsers[msg.sender] != true); 25 | _; 26 | } 27 | 28 | /** 29 | * @dev Sets the contract's version 30 | */ 31 | function setVersion(uint _version) public onlyOwner { 32 | version = _version; 33 | } 34 | 35 | /** 36 | * @dev Allows the user to migrate itself to a new contract. 37 | * @param _newContract The address of the contract to transfer the user to. 38 | * It checks if the new contract has a valid mayor version. 39 | */ 40 | function migrateUser(Versioned _newContract) public notMigrated { 41 | require(_newContract.version() > version); 42 | migratedUsers[msg.sender] = true; 43 | emit UserMigrated(msg.sender, _newContract); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/+battle/battle.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { RouterModule } from "@angular/router"; 5 | import { TranslateModule } from "@ngx-translate/core"; 6 | 7 | import { BattleComponent } from "./battle.component"; 8 | 9 | import { BattleArmySelectionComponent } from './army-selection/army-selection.component'; 10 | import { BattleArmyStatsComponent } from './army-stats/army-stats.component'; 11 | import { BattleHistoryComponent } from './+history/history.component'; 12 | import { BattleTargetComponent } from './+target/target.component'; 13 | import { TargetsListComponent } from './targets-list/targets-list.component'; 14 | 15 | import { PipesModule } from '../shared/pipes/pipes.module'; 16 | 17 | @NgModule({ 18 | imports: [ 19 | CommonModule, 20 | FormsModule, 21 | RouterModule, 22 | TranslateModule, 23 | PipesModule 24 | ], 25 | declarations: [ 26 | BattleComponent, 27 | BattleArmySelectionComponent, 28 | BattleArmyStatsComponent, 29 | BattleHistoryComponent, 30 | BattleTargetComponent, 31 | TargetsListComponent, 32 | ], 33 | exports: [ 34 | ], 35 | schemas: [CUSTOM_ELEMENTS_SCHEMA] 36 | }) 37 | export class BattleModule { 38 | } 39 | -------------------------------------------------------------------------------- /src/core/assets/buildings/data/data-building.model.ts: -------------------------------------------------------------------------------- 1 | import { parseResource } from '../../../shared/util/helpers' 2 | 3 | export class DataBuilding { 4 | 5 | name: string; 6 | health: number; 7 | defense: number; 8 | attack: number; 9 | goldCapacity: number; 10 | crystalCapacity: number; 11 | goldRate: number; 12 | crystalRate: number; 13 | price: number; 14 | resource: string; 15 | blocks: number; 16 | previousLevelId: number; 17 | typeId: number; 18 | level: number; 19 | id: number; 20 | index; 21 | startBlock; 22 | endBlock; 23 | inProgress; 24 | 25 | constructor(id: number, data: any = {}) { 26 | // TODO this data should be sent as a valid json object and not the raw response from web3 27 | this.id = id; 28 | this.name = data[0]; 29 | this.health = data[1].toNumber(); 30 | this.defense = data[2].toNumber(); 31 | this.attack = data[3].toNumber(); 32 | this.goldCapacity = data[4].toNumber(); 33 | this.crystalCapacity = data[5].toNumber(); 34 | this.goldRate = data[6].toNumber(); 35 | this.crystalRate = data[7].toNumber(); 36 | this.price = data[8].toNumber(); 37 | this.resource = parseResource(data[9].toNumber()); 38 | this.blocks = data[10].toNumber(); 39 | this.previousLevelId = data[11].toNumber(); 40 | this.typeId = data[12].toNumber(); 41 | this.level = Math.floor(id / 1000) || 1; 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/app/shared/pipes/past-block-time.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { environment } from '../../../environments/environment'; 3 | 4 | @Pipe({ 5 | name: 'pastBlockTime' 6 | }) 7 | export class PastBlockTimePipe implements PipeTransform { 8 | 9 | transform(block: any): any { 10 | if (!block || block <= 0) { 11 | return 'now'; 12 | } 13 | 14 | let blockSeconds = block * environment.blockTime; 15 | let time = new Date(blockSeconds * 1000); 16 | 17 | let months = Number(time.toISOString().substr(5, 2)) - 1; 18 | let days = Number(time.toISOString().substr(8, 2)) - 1; 19 | let hours = Number(time.toISOString().substr(11, 2)); 20 | let minutes = Number(time.toISOString().substr(14, 2)); 21 | let seconds = Number(time.toISOString().substr(17, 2)); 22 | 23 | if (months < 12) { 24 | if (months < 1) { 25 | if (days < 1) { 26 | if (hours < 1) { 27 | if (minutes < 1) { 28 | return 'now'; 29 | } else { 30 | return minutes + 'm'; 31 | } 32 | } else { 33 | return hours + 'h'; 34 | } 35 | } else { 36 | return days + 'd'; 37 | } 38 | } else { 39 | return months + 'mo'; 40 | } 41 | } else { 42 | let years = months / 12; 43 | return years + 'y'; 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['ChromeHeadless'], 29 | singleRun: false, 30 | customLaunchers: { 31 | ChromeHeadless: { 32 | base: 'Chrome', 33 | flags: [ 34 | '--headless', 35 | '--disable-gpu', 36 | // Without a remote debugging port, Google Chrome exits immediately. 37 | '--remote-debugging-port=9222', 38 | ], 39 | } 40 | } 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /src/core/player/assets/units/player-units.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { Store } from '@ngrx/store'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | 7 | import { ContractsService } from '../../../shared/contracts.service'; 8 | import { Web3Service } from '../../../web3/web3.service'; 9 | 10 | @Injectable() 11 | export class PlayerUnitsService { 12 | 13 | constructor(private store: Store, 14 | private contractsService: ContractsService, 15 | private web3Service: Web3Service){ 16 | 17 | } 18 | 19 | getPlayerUnits(activeAccount: string, playerUnitsLength: number) { 20 | let indexes: any[] = []; 21 | for (var i = 0; i < playerUnitsLength; i++) { 22 | indexes.push(i); 23 | } 24 | 25 | return Observable.forkJoin( 26 | indexes.map(index => { 27 | return this.web3Service.callContract( 28 | this.contractsService.UserUnitsInstance.userUnits, 29 | [activeAccount, index, {from: activeAccount}] 30 | ).then((result) => { 31 | if (!result || result.error) { 32 | return result; 33 | } 34 | let obj = { 35 | id: result[0].toNumber(), 36 | index: index, 37 | quantity: result[1] 38 | } 39 | return obj; 40 | }) 41 | }) 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/core/player/assets/buildings/player-buildings.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerBuildingsState } from './player-buildings.state'; 2 | import { PlayerBuilding } from './player-building.model'; 3 | import { PlayerBuildingsActions } from './player-buildings.actions'; 4 | import { Status } from '../../../shared/status.model'; 5 | 6 | export function playerBuildingsReducer (state = initialPlayerBuildingsState, action: PlayerBuildingsActions.Actions) { 7 | switch (action.type) { 8 | case PlayerBuildingsActions.Types.GET_PLAYER_BUILDINGS: 9 | return Object.assign({}, state, { 10 | status: new Status({ loading: true }), 11 | }) 12 | 13 | case PlayerBuildingsActions.Types.GET_PLAYER_BUILDINGS_SUCCESS: 14 | return Object.assign({}, state, { 15 | list: action.payload, 16 | status: new Status(), 17 | }); 18 | 19 | case PlayerBuildingsActions.Types.GET_PLAYER_BUILDINGS_FAILURE: 20 | return Object.assign({}, state, { 21 | status: new Status({ error: action.payload.status.error }), 22 | }); 23 | 24 | case PlayerBuildingsActions.Types.GET_PLAYER_BUILDINGS_LENGTH: 25 | return Object.assign({}, state, { 26 | status: new Status({ loading: true }), 27 | }) 28 | 29 | case PlayerBuildingsActions.Types.GET_PLAYER_BUILDINGS_LENGTH_FAILURE: 30 | return Object.assign({}, state, { 31 | status: new Status({ error: action.payload.status.error }), 32 | }); 33 | 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/app.selectors.ts: -------------------------------------------------------------------------------- 1 | import { createSelector } from "@ngrx/store"; 2 | import { CryptoWarsState } from './app.state'; 3 | import { PlayerResourcesState } from "../core/player/resources/player-resources.state"; 4 | 5 | export const selectBuildings = (state: CryptoWarsState) => state.app.buildingsList; 6 | export const selectBlockNumber = (state: CryptoWarsState) => state.web3.lastBlock; 7 | 8 | export const selectActiveBuildings = createSelector(selectBuildings, 9 | selectBlockNumber, 10 | (buildings: any, blockNumber: number) => { 11 | let activeBuildings = buildings.filter(b => b.active || b.endBlock <= blockNumber); 12 | return activeBuildings; 13 | }) 14 | 15 | export const selectUserResources = (state: CryptoWarsState) => state.player.resources; 16 | 17 | export const selectPlayerResources = createSelector((state: CryptoWarsState) => state.player.resources, 18 | (playerResourcesState: PlayerResourcesState) => { 19 | 20 | let obj = { 21 | gold: playerResourcesState.gold - playerResourcesState.lockedGold, 22 | crystal: playerResourcesState.crystal - playerResourcesState.lockedCrystal, 23 | quantum: playerResourcesState.quantum, 24 | goldCapacity: playerResourcesState.goldCapacity, 25 | crystalCapacity: playerResourcesState.crystalCapacity, 26 | rates: playerResourcesState.rates, 27 | status: playerResourcesState.status, 28 | } 29 | 30 | return obj; 31 | }) 32 | -------------------------------------------------------------------------------- /src/app/shared/models/unit.model.ts: -------------------------------------------------------------------------------- 1 | export interface UnitMap { 2 | [unitId: string]: Unit; 3 | } 4 | 5 | export interface UnitQuantitytMap { 6 | [unitId: number]: number; 7 | } 8 | 9 | export class Unit { 10 | active: boolean; 11 | assetRequirements: any; 12 | attack: number; 13 | blocks: number; 14 | endBlock: number; 15 | defense: number; 16 | health: number; 17 | id: number; 18 | index: number; 19 | inQueue: boolean; 20 | inProgress: boolean; 21 | missingRequirements: any; 22 | name: string; 23 | price: number; 24 | quantity: number; 25 | quantityInQueue: number; 26 | resource: string; 27 | startBlock: number; 28 | waiting: boolean; 29 | 30 | constructor(data: any = {}) { 31 | this.active = data.active; 32 | this.assetRequirements = data.assetRequirements || []; 33 | this.attack = data.attack; 34 | this.blocks = data.blocks; 35 | this.endBlock = data.endBlock; 36 | this.defense = data.defense; 37 | this.health = data.health; 38 | this.id = data.id; 39 | this.index = data.index; 40 | this.inQueue = !!data.endBlock; 41 | this.inProgress = data.inProgress; 42 | this.missingRequirements = data.missingRequirements || []; 43 | this.name = data.name; 44 | this.price = data.price; 45 | this.quantity = data.quantity || 0; 46 | this.quantityInQueue = data.quantityInQueue || 0; 47 | this.resource = data.resource; 48 | this.startBlock = data.startBlock; 49 | this.waiting = data.waiting; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/core/player/assets/buildings/player-buildings.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { Store } from '@ngrx/store'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | 7 | import { ContractsService } from '../../../shared/contracts.service'; 8 | import { Web3Service } from '../../../web3/web3.service'; 9 | 10 | @Injectable() 11 | export class PlayerBuildingsService { 12 | 13 | constructor(private store: Store, 14 | private contractsService: ContractsService, 15 | private web3Service: Web3Service){ 16 | 17 | } 18 | 19 | getPlayerBuildings(activeAccount: string, playerBuildingsLength: number) { 20 | let indexes: any[] = []; 21 | for (var i = 0; i < playerBuildingsLength; i++) { 22 | indexes.push(i); 23 | } 24 | 25 | return Observable.forkJoin( 26 | indexes.map(index => { 27 | return this.web3Service.callContract( 28 | this.contractsService.UserBuildingsInstance.userBuildings, 29 | [activeAccount, index, {from: activeAccount}] 30 | ).then((result) => { 31 | if (!result || result.error) { 32 | return result; 33 | } 34 | let obj = { 35 | id: result[0].toNumber(), 36 | index: index, 37 | level: Math.floor(result[0].toNumber() / 1000) || 1, 38 | active: result[1] 39 | } 40 | return obj; 41 | }) 42 | }) 43 | ); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/+battle/battle.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1; 5 | } 6 | 7 | .battle-container { 8 | display: flex; 9 | flex-wrap: wrap; 10 | justify-content: center; 11 | padding: 3.3rem 8vw; 12 | 13 | .army-info, 14 | .battle-info { 15 | margin: 0 1.5rem; 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | .army-info { 20 | width: 21.6rem; 21 | } 22 | .battle-info { 23 | flex: 1; 24 | } 25 | 26 | .title-selection { 27 | display: flex; 28 | align-items: center; 29 | user-select: none; 30 | margin-bottom: 1.5rem; 31 | flex-shrink: 0; 32 | 33 | a, .refresh-list { 34 | color: #7F8CA3; 35 | } 36 | 37 | a { 38 | text-decoration: none; 39 | &.active { 40 | color: white; 41 | } 42 | } 43 | 44 | .refresh-list { 45 | display: flex; 46 | align-items: center; 47 | font-size: 1.4rem; 48 | font-weight: bold; 49 | cursor: pointer; 50 | 51 | .e11-icon { 52 | margin-right: .5rem; 53 | } 54 | } 55 | } 56 | 57 | .vertical-separator { 58 | width: 1px; 59 | height: 1.4rem; 60 | background-color: #7F8FA4; 61 | margin: 0 1.5rem; 62 | } 63 | } 64 | 65 | /deep/ { 66 | .battle-target-container, 67 | .battle-history-container { 68 | & > .e11-box-container { 69 | min-height: 40rem; 70 | max-height: 72vh; 71 | .box-content.empty { 72 | margin: 1rem; 73 | font-size: 2.4rem; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/app/+dashboard/village-queues/village-queues.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'e11-village-queues', 5 | templateUrl: './village-queues.component.html', 6 | styleUrls: ['./village-queues.component.scss'] 7 | }) 8 | 9 | export class VillageQueuesComponent implements OnChanges { 10 | @Input() buildingsQueue: any = []; 11 | @Input() researchQueue: any = []; 12 | @Input() unitsQueue: any = []; 13 | 14 | @Output() navigateTo: EventEmitter = new EventEmitter(); 15 | 16 | public buildingsQueueIsEmpty: boolean = true; 17 | public unitsQueueIsEmpty: boolean = true; 18 | private maxQueueItems: number = 4; 19 | 20 | constructor() { 21 | } 22 | 23 | ngOnChanges(changes: SimpleChanges) { 24 | if (changes.buildingsQueue) { 25 | this.setUnfinishedBuildings(changes.buildingsQueue.currentValue); 26 | } 27 | 28 | if (changes.unitsQueue) { 29 | this.setUnfinishedUnits(changes.unitsQueue.currentValue); 30 | } 31 | } 32 | 33 | setUnfinishedBuildings(buildings: any) { 34 | let unfinishedBuildings = buildings.filter(building => building.inProgress); 35 | this.buildingsQueueIsEmpty = unfinishedBuildings.length ? false : true; 36 | } 37 | 38 | setUnfinishedUnits(units: any) { 39 | let unfinishedUnits = units.filter(unit => unit.inProgress); 40 | this.unitsQueueIsEmpty = unfinishedUnits.length ? false : true; 41 | } 42 | 43 | trackByFn(index, item) { 44 | return item.id; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/helpers/setContractsTest.js: -------------------------------------------------------------------------------- 1 | const { assertRevert } = require('./assertThrow'); 2 | const AssetsRequirements = artifacts.require('AssetsRequirements'); 3 | const BuildingsData = artifacts.require('BuildingsData'); 4 | const BuildingsQueue = artifacts.require('BuildingsQueue'); 5 | const ExperimentalToken = artifacts.require('ExperimentalToken'); 6 | const UserBuildings = artifacts.require('UserBuildings'); 7 | const UserResources = artifacts.require('UserResources'); 8 | const UserVault = artifacts.require('UserVault'); 9 | const UserVillage = artifacts.require('UserVillage'); 10 | 11 | module.exports = { 12 | setContractsTest: async (instance) => { 13 | let basicToken = await ExperimentalToken.new(); 14 | let contracts = { 15 | 'AssetsRequirements': await AssetsRequirements.new(), 16 | 'BuildingsData': await BuildingsData.new(), 17 | 'BuildingsQueue': await BuildingsQueue.new(), 18 | 'UserBuildings': await UserBuildings.new(), 19 | 'UserResources': await UserResources.new(), 20 | 'UserVault': await UserVault.new(), 21 | 'UserVillage': await UserVillage.new(), 22 | }; 23 | 24 | for (let contractName in contracts) { 25 | if (contracts.hasOwnProperty(contractName)) { 26 | if(instance[`set${contractName}`]) { 27 | await instance[`set${contractName}`](contracts[contractName].address); 28 | await assertRevert(async () => { 29 | await instance[`set${contractName}`](basicToken.address); 30 | }); 31 | } 32 | } 33 | } 34 | 35 | return true; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /data/test/units.json: -------------------------------------------------------------------------------- 1 | { 2 | "unitProperties":{ 3 | "id": 0, 4 | "name": "x", 5 | "stats": [ 6 | "health", "defense", "attack", 7 | "price", "resource", "blocks" 8 | ] 9 | }, 10 | "stats": { 11 | "health": 0, "defense": 1, "attack": 2, 12 | "price": 3, "resource": 4, "blocks": 5 13 | }, 14 | "initialUnits": [{ 15 | "id": 1, 16 | "name": "tiny_warrior", 17 | "requirements": [ 18 | 1009 19 | ], 20 | "stats": [ 21 | 200, 25, 150, 22 | 100, 0, 1 23 | ] 24 | },{ 25 | "id": 2, 26 | "name": "archer", 27 | "requirements": [ 28 | 2009 29 | ], 30 | "stats": [ 31 | 100, 20, 250, 32 | 200, 0, 2 33 | ] 34 | },{ 35 | "id": 3, 36 | "name": "guardian", 37 | "requirements": [ 38 | 3009 39 | ], 40 | "stats": [ 41 | 500, 250, 50, 42 | 500, 0, 4 43 | ] 44 | },{ 45 | "id": 4, 46 | "name": "reptilian", 47 | "requirements": [ 48 | 49 | ], 50 | "stats": [ 51 | 500, 50, 250, 52 | 50, 1, 1 53 | ] 54 | },{ 55 | "id": 5, 56 | "name": "kitty", 57 | "requirements": [ 58 | 59 | ], 60 | "stats": [ 61 | 500, 50, 250, 62 | 20, 2, 5 63 | ] 64 | },{ 65 | "id": 6, 66 | "name": "knight", 67 | "requiements": [ 68 | 69 | ], 70 | "stats": [ 71 | 1, 1, 2, 72 | 20, 0, 5 73 | ] 74 | },{ 75 | "id": 7, 76 | "name": "protector", 77 | "requiements": [ 78 | ], 79 | "stats": [ 80 | 1, 2, 1, 81 | 20, 0, 5 82 | ] 83 | }] 84 | } 85 | -------------------------------------------------------------------------------- /src/app/+battle/+target/target.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | {{'BATTLE.LOADING.targets' | translate}} 6 | 7 | 8 | {{'BATTLE.TARGETS.not-found' | translate}} 9 | 10 | 11 | {{'BATTLE.no-army' | translate}} 12 | 13 |
14 | 15 | 16 | 23 | 24 | 25 |
26 |
27 | 28 | {{'BATTLE.TARGETS.find-more' | translate}} 29 | 30 | 31 | {{'BATTLE.LOADING.more-targets' | translate}} 32 | 33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /src/app/+onboarding/new-user/new-user.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | .new-user-container { 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | padding-top: 10vh; 8 | 9 | .logo-simple { 10 | width: 48rem; 11 | max-width: $app-errors-container-max-width; 12 | margin-bottom: 7rem; 13 | } 14 | 15 | .e11-box-container { 16 | width: 37rem; 17 | flex-shrink: 0; 18 | max-width: $app-errors-container-max-width * 2; 19 | margin-bottom: 10vh; 20 | 21 | .box-content { 22 | .box-option { 23 | padding: 1.4rem; 24 | &.input { 25 | padding: 2rem 2.6rem; 26 | } 27 | } 28 | } 29 | } 30 | 31 | .creating-village { 32 | display: flex; 33 | flex-direction: column; 34 | align-items: center; 35 | 36 | .loading-bar { 37 | display: flex; 38 | align-items: center; 39 | justify-content: center; 40 | font-weight: 500; 41 | border-radius: $app-default-radius; 42 | height: 6.3rem; 43 | width: 60rem; 44 | margin-bottom: 3rem; 45 | 46 | &, span { 47 | font-size: 2rem; 48 | font-weight: bold; 49 | color: $color-text; 50 | } 51 | span { 52 | margin-left: 5px; 53 | cursor: pointer; 54 | } 55 | 56 | &.pending { 57 | background: $color-success; 58 | } 59 | &.failed { 60 | background: $color-error; 61 | } 62 | } 63 | 64 | span { 65 | font-size: 1.4rem; 66 | color: $color-text-grey; 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/app/app.state.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ActionReducerMap, 3 | ActionReducer, 4 | combineReducers, 5 | compose, 6 | MetaReducer 7 | } from '@ngrx/store'; 8 | // TODO Clean unused imports 9 | import "rxjs/add/operator/let"; 10 | import "rxjs/add/operator/switchMap"; 11 | 12 | import { environment } from "../environments/environment"; 13 | import { storeFreeze } from "ngrx-store-freeze"; 14 | 15 | import { Building } from './shared/models/building.model'; 16 | import { Unit, UnitMap } from './shared/models/unit.model'; 17 | 18 | // States and Reducers 19 | import { appReducer } from './app.reducer'; 20 | 21 | import { AssetsState } from '../core/assets/assets.state'; 22 | import { PlayerState } from '../core/player/player.state'; 23 | import { Web3State } from '../core/web3/web3.state'; 24 | 25 | export interface AppState { 26 | buildingsList: Building[]; 27 | initialized: boolean; 28 | unitsList: Unit[]; 29 | unitsMap: UnitMap; 30 | } 31 | 32 | export const initialAppState = { 33 | buildingsList: [], 34 | initialized: false, 35 | unitsList: [], 36 | unitsMap: {}, 37 | } 38 | 39 | export interface CryptoWarsState { 40 | app: AppState, 41 | assets: AssetsState, 42 | player: PlayerState, 43 | web3: Web3State, 44 | } 45 | 46 | /** 47 | * By default, @ngrx/store uses combineReducers with the reducer map to compose 48 | * the root meta-reducer. To add more meta-reducers, provide an array of meta-reducers 49 | * that will be composed to form the root meta-reducer. 50 | */ 51 | export const metaReducers: MetaReducer[] = !environment.production 52 | ? [storeFreeze] : []; 53 | -------------------------------------------------------------------------------- /src/app/+battle/targets-list/targets-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, EventEmitter, Output } from '@angular/core'; 2 | 3 | import { BattleDetail } from '../../../core/player/battle/battle-detail.model'; 4 | import { PlayerTarget } from '../../../core/player/targets/player-target.model'; 5 | import { UnitMap } from '../../shared/models/unit.model'; 6 | 7 | @Component({ 8 | selector: 'e11-targets-list', 9 | templateUrl: './targets-list.component.html', 10 | styleUrls: ['./targets-list.component.scss'] 11 | }) 12 | 13 | export class TargetsListComponent { 14 | 15 | @Input() battleDetails: BattleDetail[] = []; 16 | @Input() targetsMap: any = {}; 17 | @Input() unitsMap: UnitMap = {}; 18 | @Input() attackCooldown: number = 0; 19 | @Input() expandedBattleId: string = ''; 20 | 21 | @Output() battleDetailClicked: EventEmitter = new EventEmitter(); 22 | @Output() battleDetailEmitter: EventEmitter = new EventEmitter(); 23 | 24 | statsName: string[] = ['dmg', 'def', 'hp']; 25 | resources: string[] = ['gold', 'crystal', 'quantum']; 26 | 27 | constructor() { 28 | } 29 | 30 | expandBattleDetail(id: string) { 31 | this.battleDetailEmitter.emit(id); 32 | } 33 | 34 | collapseBattleDetail(id: string) { 35 | if (!this.expandedBattleId || this.expandedBattleId != id) { 36 | this.battleDetailEmitter.emit(id); 37 | return; 38 | } 39 | this.battleDetailEmitter.emit(''); 40 | } 41 | 42 | trackByFn(index, battleDetail) { 43 | return battleDetail.village.address; 44 | } 45 | 46 | battleDetailAction(battleDetail: BattleDetail) { 47 | this.battleDetailClicked.emit(battleDetail); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | let mainnetProvider, e11Provider; 2 | 3 | if (!process.env.SOLIDITY_COVERAGE && !process.env.SOLIDITY_TEST) { 4 | const PrivateKeyProvider = require('truffle-privatekey-provider'); 5 | const deployConfig = require('./mocks/deploy-config'); 6 | 7 | mainnetProvider = new PrivateKeyProvider(deployConfig.mainnet.privateKey, deployConfig.mainnet.endpoint); 8 | e11Provider = new PrivateKeyProvider(deployConfig.e11.privateKey, deployConfig.e11.endpoint); 9 | } 10 | 11 | let exportConfig = { 12 | networks: { 13 | development: { 14 | host: "localhost", 15 | port: 8545, 16 | gas: 7000000, 17 | network_id: "*" 18 | }, 19 | mainnet: { 20 | provider: mainnetProvider, 21 | gasPrice: 10000000000, 22 | network_id: "1" 23 | }, 24 | e11: { 25 | provider: e11Provider, 26 | gasPrice: 1000000000, 27 | network_id: "311001" 28 | }, 29 | ganache: { 30 | host: "localhost", 31 | port: 8345, 32 | gas: 7000000, 33 | network_id: "*" 34 | }, 35 | coverage: { 36 | host: "localhost", 37 | network_id: "*", 38 | port: 8355, // <-- Use port 8555 39 | gas: 0xfffffffffff, // <-- Use this high gas value 40 | gasPrice: 0x01 // <-- Use this low gas price 41 | } 42 | }, 43 | solc: { 44 | optimizer: { 45 | enabled: true, 46 | runs: 200 47 | } 48 | } 49 | }; 50 | 51 | if (!process.env.SOLIDITY_COVERAGE && !process.env.SOLIDITY_TEST) { 52 | exportConfig.mocha = { 53 | reporter: 'eth-gas-reporter', 54 | reporterOptions : { 55 | currency: 'USD', 56 | } 57 | }; 58 | } 59 | 60 | module.exports = exportConfig; 61 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_badge.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-badge() { 2 | 3 | $badge-border-radius: 18px; 4 | $badge-background: #90969F; 5 | $badge-color: $color-text; 6 | $badge-font-size: 1.5rem; 7 | $badge-padding: 4px 9px; 8 | $badge-shadow: 0 -1px 0 0 #E6EAEE; 9 | 10 | $badge-points-background: #7F8CA3; 11 | $badge-points-font-size: .9rem; 12 | $badge-points-font-size-medium: 1rem; 13 | 14 | .e11-badge { 15 | @extend .noselect; 16 | 17 | display: flex; 18 | align-items: center; 19 | justify-content: center; 20 | border-radius: $badge-border-radius; 21 | font-size: $badge-font-size; 22 | padding: $badge-padding; 23 | background: $badge-background; 24 | color: $badge-color; 25 | box-shadow: $badge-shadow; 26 | cursor: default; 27 | } 28 | 29 | .e11-points-badge { 30 | display: flex; 31 | align-items: center; 32 | justify-content: center; 33 | background-color: $badge-points-background; 34 | color: $badge-color; 35 | border-radius: 10rem; 36 | font-size: $badge-points-font-size; 37 | font-weight: bold; 38 | line-height: normal; 39 | text-align: center; 40 | padding: .1rem .6rem; 41 | white-space: nowrap; 42 | cursor: default; 43 | 44 | .e11-icon { 45 | margin-right: .5rem; 46 | font-size: 1rem; 47 | } 48 | 49 | &[position="bottom"] { 50 | position: absolute; 51 | bottom: -.5rem; 52 | } 53 | &[size='medium'] { 54 | font-size: 1rem; 55 | padding: .2rem .7rem; 56 | 57 | .e11-icon { 58 | font-size: 1.1rem; 59 | } 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /test/helpers/getParams.js: -------------------------------------------------------------------------------- 1 | let userResources; 2 | let userUnits; 3 | 4 | module.exports = { 5 | setUserResources: (_userResources) => { 6 | userResources = _userResources; 7 | }, 8 | 9 | setUserUnits: (_userUnits) => { 10 | userUnits = _userUnits; 11 | }, 12 | 13 | getParams: async (Alice, Bob) => { 14 | let [alice_gold, alice_crystal] = await userResources.getUserResources.call(Alice); 15 | let [bob_gold, bob_crystal] = await userResources.getUserResources.call(Bob); 16 | let [bob_gold_capacity, bob_crystal_capacity] = await userResources.calculateUserResourcesCapacity.call(Bob); 17 | 18 | alice_gold = alice_gold.toNumber(); 19 | alice_crystal = alice_crystal.toNumber(); 20 | bob_gold = bob_gold.toNumber(); 21 | bob_crystal = bob_crystal.toNumber(); 22 | bob_gold_capacity = bob_gold_capacity.toNumber(); 23 | bob_crystal_capacity = bob_crystal_capacity.toNumber(); 24 | 25 | let [alice_units_ids, alice_units_quanities] = await userUnits.getUserUnitsAndQuantities.call(Alice); 26 | let [bob_units_ids, bob_units_quanities] = await userUnits.getUserUnitsAndQuantities.call(Bob); 27 | 28 | // alice_units_ids = alice_units_ids.map(id => id.toNumber()); 29 | // alice_units_quanities = alice_units_quanities.map(q => q.toNumber()); 30 | // bob_units_ids = bob_units_ids.map(id => id.toNumber()); 31 | // bob_units_quanities = bob_units_quanities.map(q => q.toNumber()); 32 | 33 | return { 34 | alice_gold, 35 | alice_crystal, 36 | bob_gold, 37 | bob_crystal, 38 | bob_gold_capacity, 39 | bob_crystal_capacity, 40 | alice_units_ids, 41 | alice_units_quanities, 42 | bob_units_ids, 43 | bob_units_quanities 44 | }; 45 | }, 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 0.1.12 / 2018-08-15 4 | ================== 5 | 6 | * Re-enable coverage 7 | * Fixed Quantum dust translation 8 | 9 | 0.1.11 / 2018-08-8 10 | ================== 11 | 12 | * Village Logs 13 | * Battle System 14 | * Revenge System 15 | * Points System 16 | * Game balancing 17 | * Upgraded contracts to pragma 0.4.24 18 | * Scripts generate-buildings, update-buildings, and populate-poa 19 | 20 | 0.1.10 / 2018-04-27 21 | ================== 22 | 23 | * Fixed travis 24 | 25 | 0.1.9 / 2018-04-27 26 | ================== 27 | 28 | * Improvements on travis-ci 29 | * Fixed AoT 30 | * Fixed bug on buildings component 31 | 32 | 0.1.8 / 2018-04-26 33 | ================== 34 | 35 | * Units Creation 36 | * Small improvements on cards design 37 | * Improvements on the internal ngrx core 38 | * Changes on how we display and manage the requirements 39 | * Upgraded contracts to pragma 0.4.23 40 | * Small improvements on the UI 41 | 42 | 0.1.7 / 2018-03-20 43 | ================== 44 | 45 | * Assets Requirements 46 | * Fix send tokens script 47 | * Fix migration 48 | * Evnm mine helper added 49 | 50 | 0.1.6 / 2018-03-15 51 | ================== 52 | 53 | * Resources capacity implemented 54 | * Fixed end block for building construction 55 | * Faster migration 56 | * Remove building function removed from Buildings Queue Contract 57 | 58 | 0.1.5 / 2018-02-21 59 | ================== 60 | 61 | * New web design + NgRx State Management 62 | * Contracts are now versioned and have their own type for checks 63 | * Metamask error handling 64 | * Abstracted remote & local contracts into environments 65 | * Alice does not act as a contract anymore 66 | * E11 PoA network (311) 67 | * First alpha release v0.1.5 68 | -------------------------------------------------------------------------------- /src/app/+battle/army-stats/army-stats.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import 'rxjs/add/observable/combineLatest'; 5 | 6 | 7 | import { CryptoWarsState } from '../../app.state'; 8 | 9 | import { AbstractContainerComponent } from '../../shared/components/abstract-container.component'; 10 | 11 | import { Unit, /*UnitMap,*/ UnitQuantitytMap } from '../../shared/models/unit.model'; 12 | 13 | 14 | @Component({ 15 | selector: 'e11-battle-army-stats', 16 | templateUrl: './army-stats.component.html', 17 | styleUrls: ['./army-stats.component.scss'] 18 | }) 19 | 20 | export class BattleArmyStatsComponent extends AbstractContainerComponent { 21 | units: Unit[] = []; 22 | armyStats: any = { 23 | hp: 0, 24 | attack: 0, 25 | defense: 0, 26 | }; 27 | 28 | 29 | constructor(public store: Store) { 30 | super(store); 31 | 32 | this.addToSubscriptions( 33 | this.setUnitsMap() 34 | ); 35 | } 36 | 37 | 38 | setUnitsMap() { 39 | return Observable.combineLatest( 40 | this.store.select(s => s.assets.units.data.listMap).distinctUntilChanged(), 41 | this.store.select(s => s.player.army).distinctUntilChanged(), 42 | ).subscribe(data => { 43 | let listMap = data[0]; 44 | let army = data[1]; 45 | let keys = Object.keys(army); 46 | 47 | let hp = 0 48 | let attack = 0 49 | let defense = 0 50 | keys.forEach(id => { 51 | hp += listMap[id].health * army[id]; 52 | attack += listMap[id].attack * army[id]; 53 | defense += listMap[id].defense * army[id]; 54 | }) 55 | 56 | this.armyStats = Object.assign({}, this.armyStats, {hp, attack, defense}); 57 | }) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/core/assets/units/queue/units-queue.reducer.ts: -------------------------------------------------------------------------------- 1 | import { AssetsUnitsQueueActions } from './units-queue.actions'; 2 | import { initialAssetsUnitsQueueState } from './units-queue.state'; 3 | import { Status } from '../../../shared/status.model'; 4 | 5 | export function assetsUnitsQueueReducer (state = initialAssetsUnitsQueueState, action: AssetsUnitsQueueActions.Actions) { 6 | switch (action.type) { 7 | 8 | case AssetsUnitsQueueActions.Types.GET_UNITS_QUEUE: 9 | return Object.assign({}, state, { 10 | status: new Status({ loading: true }), 11 | }) 12 | 13 | case AssetsUnitsQueueActions.Types.GET_UNITS_QUEUE_SUCCESS: 14 | return Object.assign({}, state, { 15 | list: action.payload, 16 | status: new Status(), 17 | }) 18 | 19 | case AssetsUnitsQueueActions.Types.GET_UNITS_QUEUE_FAILURE: 20 | return Object.assign({}, state, { 21 | status: new Status({ error: action.payload.status.error }), 22 | }) 23 | 24 | case AssetsUnitsQueueActions.Types.ADD_UNIT_TO_QUEUE: 25 | return Object.assign({}, state, { 26 | localList: state.localList.concat([action.payload.id]), 27 | status: new Status({ loading: true }), 28 | }) 29 | 30 | case AssetsUnitsQueueActions.Types.ADD_UNIT_TO_QUEUE_SUCCESS: 31 | return Object.assign({}, state, { 32 | localList: state.localList.filter(unit => unit != action.payload.id), 33 | status: new Status(), 34 | }) 35 | 36 | case AssetsUnitsQueueActions.Types.ADD_UNIT_TO_QUEUE_FAILURE: 37 | return Object.assign({}, state, { 38 | localList: state.localList.filter(unit => unit != action.payload.id), 39 | status: new Status({ error: action.payload.status.error }), 40 | }) 41 | 42 | default: 43 | return state; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/app/+battle/battle.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { Store } from '@ngrx/store'; 4 | 5 | import { PlayerTargetsActions } from '../../core/player/targets/player-targets.actions'; 6 | import { PlayerVillageService } from '../../core/player/village/player-village.service'; 7 | 8 | import { PlayerTarget } from '../../core/player/targets/player-target.model'; 9 | import { PlayerBattleActions } from '../../core/player/battle/player-battle.actions'; 10 | import { PlayerBattleService } from '../../core/player/battle/player-battle.service'; 11 | 12 | import { AbstractContainerComponent } from '../shared/components/abstract-container.component'; 13 | 14 | @Component({ 15 | selector: 'e11-battle', 16 | templateUrl: './battle.component.html', 17 | styleUrls: ['./battle.component.scss'] 18 | }) 19 | 20 | export class BattleComponent extends AbstractContainerComponent { 21 | 22 | targets: PlayerTarget[] = []; 23 | 24 | constructor(public store: Store, 25 | private activatedRoute: ActivatedRoute, 26 | private playerVillageService: PlayerVillageService, 27 | private playerBattleService: PlayerBattleService) { 28 | super(store); 29 | 30 | } 31 | 32 | refresh() { 33 | let activatedRoute = this.activatedRoute.children[this.activatedRoute.children.length - 1]; 34 | if (activatedRoute.routeConfig.path === 'target') { 35 | this.store.dispatch(new PlayerTargetsActions.ClearTargets()); 36 | this.store.dispatch(new PlayerTargetsActions.GetTargets()); 37 | } 38 | if (activatedRoute.routeConfig.path === 'history') { 39 | this.store.dispatch(new PlayerBattleActions.ClearBattleHistory()); 40 | this.store.dispatch(new PlayerBattleActions.GetBattleHistory()); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/assets/e11-theme/components/_segments.scss: -------------------------------------------------------------------------------- 1 | @mixin e11-segments() { 2 | $segment-radius: $app-default-radius; 3 | $segment-border-color: $color-border; 4 | $segment-default-width: 19rem; 5 | $segment-default-padding: 1.4rem; 6 | $segment-small-padding: .9rem 1.4rem; 7 | 8 | .e11-segments { 9 | @extend .noselect; 10 | display: flex; 11 | flex-shrink: 0; 12 | 13 | &[size='small'] { 14 | .e11-segment { 15 | font-size: 1.2rem; 16 | width: auto; 17 | padding: $segment-small-padding; 18 | } 19 | } 20 | 21 | .e11-segment { 22 | @extend .flex, .centered; 23 | background: $color-dark-alt; 24 | color: $color-light; 25 | border: 1px solid $segment-border-color; 26 | font-size: 1.4rem; 27 | font-weight: bold; 28 | width: 19rem; 29 | outline: none; 30 | text-transform: uppercase; 31 | white-space: nowrap; 32 | padding: $segment-default-padding; 33 | cursor: pointer; 34 | 35 | 36 | &.active { 37 | color: $color-text; 38 | background: $color-contrast; 39 | border-color: $color-contrast-light; 40 | } 41 | 42 | &:first-child { 43 | border-top-left-radius: $segment-radius; 44 | border-bottom-left-radius: $segment-radius; 45 | } 46 | &:last-child { 47 | border-top-right-radius: $segment-radius; 48 | border-bottom-right-radius: $segment-radius; 49 | } 50 | 51 | .e11-icon { 52 | font-size: 1.6rem; 53 | margin-right: 1rem; 54 | } 55 | 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/core/player/assets/buildings/player-buildings.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../../shared/util/type'; 3 | 4 | export namespace PlayerBuildingsActions { 5 | 6 | export const Types = { 7 | GET_PLAYER_BUILDINGS: type('[Player Buildings] Get Player Buildings'), 8 | GET_PLAYER_BUILDINGS_SUCCESS: type('[Player Buildings] Get Player Buildings Success'), 9 | GET_PLAYER_BUILDINGS_FAILURE: type('[Player Buildings] Get Player Buildings Failure'), 10 | GET_PLAYER_BUILDINGS_LENGTH: type('[Player Buildings] Get Player Buildings Length'), 11 | GET_PLAYER_BUILDINGS_LENGTH_FAILURE: type('[Player Buildings] Get Player Buildings Length Failure'), 12 | } 13 | 14 | export class GetPlayerBuildings implements Action { 15 | type = Types.GET_PLAYER_BUILDINGS; 16 | 17 | constructor(public payload: number) { } 18 | } 19 | 20 | export class GetPlayerBuildingsSuccess implements Action { 21 | type = Types.GET_PLAYER_BUILDINGS_SUCCESS; 22 | 23 | constructor(public payload: any[]) { } 24 | } 25 | 26 | export class GetPlayerBuildingsFailure implements Action { 27 | type = Types.GET_PLAYER_BUILDINGS_FAILURE; 28 | 29 | constructor(public payload: any) { } 30 | } 31 | 32 | export class GetPlayerBuildingsLength implements Action { 33 | type = Types.GET_PLAYER_BUILDINGS_LENGTH; 34 | payload; 35 | 36 | constructor() { } 37 | } 38 | 39 | export class GetPlayerBuildingsLengthFailure implements Action { 40 | type = Types.GET_PLAYER_BUILDINGS_LENGTH_FAILURE; 41 | 42 | constructor(public payload: any) { } 43 | } 44 | 45 | 46 | export type Actions 47 | = GetPlayerBuildings 48 | | GetPlayerBuildingsSuccess 49 | | GetPlayerBuildingsFailure 50 | | GetPlayerBuildingsLength 51 | | GetPlayerBuildingsLengthFailure 52 | } 53 | -------------------------------------------------------------------------------- /src/core/assets/assets.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { StoreModule } from '@ngrx/store'; 3 | import { EffectsModule } from '@ngrx/effects'; 4 | 5 | import { assetsReducerProvider, assetsReducerToken, initialAssetsState } from './assets.state'; 6 | import { AssetsBuildingsDataEffects } from './buildings/data/buildings-data.effects'; 7 | import { AssetsBuildingsDataService } from './buildings/data/buildings-data.service'; 8 | import { AssetsBuildingsQueueEffects } from './buildings/queue/buildings-queue.effects'; 9 | import { AssetsRequirementsEffects } from './requirements/assets-requirements.effects'; 10 | import { AssetsRequirementsService } from './requirements/assets-requirements.service'; 11 | import { AssetsUnitsDataEffects } from './units/data/units-data.effects'; 12 | import { AssetsUnitsDataService } from './units/data/units-data.service'; 13 | import { AssetsUnitsQueueEffects } from './units/queue/units-queue.effects'; 14 | 15 | @NgModule({ 16 | imports: [ 17 | StoreModule.forFeature('assets', assetsReducerToken, { 18 | initialState: initialAssetsState 19 | }), 20 | EffectsModule.forFeature([ 21 | AssetsBuildingsDataEffects, 22 | AssetsBuildingsQueueEffects, 23 | AssetsRequirementsEffects, 24 | AssetsUnitsDataEffects, 25 | AssetsUnitsQueueEffects, 26 | ]) 27 | ], 28 | providers: [ 29 | AssetsBuildingsDataService, 30 | AssetsRequirementsService, 31 | AssetsUnitsDataService, 32 | assetsReducerProvider, 33 | ] 34 | }) 35 | export class AssetsCoreModule { 36 | static forRoot(): ModuleWithProviders { 37 | return { 38 | ngModule: AssetsCoreModule, 39 | providers: [ 40 | AssetsBuildingsDataService, 41 | AssetsRequirementsService, 42 | AssetsUnitsDataService, 43 | assetsReducerProvider, 44 | ] 45 | }; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/player/tokens/player-tokens.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerTokensState } from './player-tokens.state'; 2 | import { PlayerTokensActions } from './player-tokens.actions'; 3 | import { Status } from '../../shared/status.model'; 4 | 5 | export function playerTokensReducer (state = initialPlayerTokensState, action: PlayerTokensActions.Actions) { 6 | switch (action.type) { 7 | 8 | case PlayerTokensActions.Types.GET_ETH_BALANCE: 9 | return Object.assign({}, state, { 10 | status: new Status({ 11 | error: null, 12 | loading: true 13 | }) 14 | }) 15 | 16 | case PlayerTokensActions.Types.GET_ETH_BALANCE_SUCCESS: 17 | return Object.assign({}, state, { 18 | ethBalance: action.payload / Math.pow(10, 18), 19 | status: new Status() 20 | }); 21 | 22 | case PlayerTokensActions.Types.GET_ETH_BALANCE_FAILURE: 23 | return Object.assign({}, state, { 24 | status: new Status({ error: action.payload.status.error }) 25 | }); 26 | 27 | case PlayerTokensActions.Types.GET_E11_BALANCE: 28 | return Object.assign({}, state, { 29 | status: new Status({ 30 | error: null, 31 | loading: true 32 | }) 33 | }) 34 | 35 | case PlayerTokensActions.Types.GET_E11_BALANCE_SUCCESS: 36 | return Object.assign({}, state, { 37 | e11Balance: action.payload / Math.pow(10, 18), 38 | status: new Status({ loading: false }) 39 | }); 40 | 41 | case PlayerTokensActions.Types.GET_E11_BALANCE_SUCCESS: 42 | return Object.assign({}, state, { 43 | status: new Status({ error: action.payload }) 44 | }); 45 | 46 | case PlayerTokensActions.Types.GET_E11_BALANCE_FAILURE: 47 | return Object.assign({}, state, { 48 | status: new Status({ error: action.payload.status.error }) 49 | }); 50 | 51 | default: 52 | return state; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/core/assets/units/queue/units-queue.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../../shared/util/type'; 3 | 4 | export namespace AssetsUnitsQueueActions { 5 | 6 | export const Types = { 7 | GET_UNITS_QUEUE: type('[Units Queue] Get User Units Queue'), 8 | GET_UNITS_QUEUE_SUCCESS: type('[Units Queue] Get User Units Queue Success'), 9 | GET_UNITS_QUEUE_FAILURE: type('[Units Queue] Get User Units Queue Failure'), 10 | ADD_UNIT_TO_QUEUE: type('[Units Queue] Add Unit To Queue'), 11 | ADD_UNIT_TO_QUEUE_SUCCESS: type('[Units Queue] Add Unit To Queue Success'), 12 | ADD_UNIT_TO_QUEUE_FAILURE: type('[Units Queue] Add Unit To Queue Failure'), 13 | } 14 | 15 | export class GetUnitsQueue implements Action { 16 | type = Types.GET_UNITS_QUEUE; 17 | 18 | constructor(public payload: string) { } 19 | } 20 | 21 | export class GetUnitsQueueSuccess implements Action { 22 | type = Types.GET_UNITS_QUEUE_SUCCESS; 23 | 24 | constructor(public payload: any) { } 25 | } 26 | 27 | export class GetUnitsQueueFailure implements Action { 28 | type = Types.GET_UNITS_QUEUE_FAILURE; 29 | 30 | constructor(public payload: any) { } 31 | } 32 | 33 | export class AddUnitToQueue implements Action { 34 | type = Types.ADD_UNIT_TO_QUEUE; 35 | 36 | constructor(public payload: any) { } 37 | } 38 | 39 | export class AddUnitToQueueSuccess implements Action { 40 | type = Types.ADD_UNIT_TO_QUEUE_SUCCESS; 41 | 42 | constructor(public payload: any) { } 43 | } 44 | 45 | export class AddUnitToQueueFailure implements Action { 46 | type = Types.ADD_UNIT_TO_QUEUE_FAILURE; 47 | 48 | constructor(public payload: any) { } 49 | } 50 | 51 | export type Actions 52 | = GetUnitsQueue 53 | | GetUnitsQueueSuccess 54 | | GetUnitsQueueFailure 55 | | AddUnitToQueue 56 | | AddUnitToQueueSuccess 57 | | AddUnitToQueueFailure 58 | 59 | } 60 | -------------------------------------------------------------------------------- /test/VersionedTest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const { assertRevert } = require('./helpers/assertThrow'); 3 | 4 | const Versioned = artifacts.require('Versioned'); 5 | 6 | contract('Versioned', function(accounts) { 7 | let versioned; 8 | const Alice = accounts[0]; 9 | const Bob = accounts[1]; 10 | 11 | beforeEach(async function() { 12 | versioned = await Versioned.new(); 13 | }); 14 | 15 | it('should not have version', async function() { 16 | let version = await versioned.version(); 17 | assert.isTrue(version.toNumber() === 0); 18 | }); 19 | 20 | it('should set version', async function() { 21 | await versioned.setVersion(1); 22 | let version = await versioned.version(); 23 | assert.isTrue(version.toNumber() === 1); 24 | }); 25 | 26 | it('should not allow to set version if not an owner', async function() { 27 | await assertRevert(async () => { 28 | await versioned.setVersion(1, {from: Bob}); 29 | }); 30 | }); 31 | 32 | it('should not allow to migrate user', async function() { 33 | let versioned2 = await Versioned.new(); 34 | await assertRevert(async () => { 35 | await versioned.migrateUser(versioned2.address); 36 | }); 37 | }); 38 | 39 | it('should allow to migrate user', async function() { 40 | let versioned2 = await Versioned.new(); 41 | await versioned2.setVersion(1); 42 | await versioned.migrateUser(versioned2.address); 43 | let migrated = await versioned.migratedUsers.call(Alice); 44 | assert.isTrue(migrated); 45 | }); 46 | 47 | it('should not allow to migrate user more than once', async function() { 48 | let versioned2 = await Versioned.new(); 49 | await versioned2.setVersion(1); 50 | await versioned.migrateUser(versioned2.address); 51 | let migrated = await versioned.migratedUsers.call(Alice); 52 | await assertRevert(async () => { 53 | await versioned.migrateUser(versioned2.address); 54 | }); 55 | }); 56 | 57 | }); 58 | -------------------------------------------------------------------------------- /src/app/+assets/queue-navbar/queue-navbar.component.scss: -------------------------------------------------------------------------------- 1 | @import 'src/assets/e11-theme/variables'; 2 | 3 | .queue-navbar-container { 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | margin-top: 3rem; 8 | 9 | .queue-navbar { 10 | display: flex; 11 | align-items: center; 12 | flex-direction: row; 13 | padding: 0 2.5rem; 14 | height: 7rem; 15 | flex: 1; 16 | 17 | .v-separator { 18 | height: 1.4rem; 19 | margin: 0 1.5rem; 20 | width: 1px; 21 | background: $color-text-grey; 22 | } 23 | span { 24 | color: $color-text-grey; 25 | font-size: 1.4rem; 26 | } 27 | 28 | .queue-items { 29 | display: flex; 30 | flex: 1; 31 | 32 | .item { 33 | width: 5rem; 34 | height: 5rem; 35 | margin-left: -1.4rem; 36 | position: relative; 37 | 38 | &[tooltip]:before { 39 | white-space: nowrap; 40 | } 41 | &:hover { 42 | .hover-action { 43 | display: flex; 44 | } 45 | } 46 | &:first-child { 47 | margin-left: 0; 48 | } 49 | 50 | & > * { 51 | border-radius: 100%; 52 | } 53 | 54 | .item-image { 55 | border: 5px solid $color-light-alt; 56 | background-position: center; 57 | background-size: cover; 58 | width: 100%; 59 | height: 100%; 60 | } 61 | 62 | .hover-action, .ready { 63 | position: absolute; 64 | top: 0; 65 | } 66 | 67 | .hover-action { 68 | font-size: 1.6rem; 69 | } 70 | .ready { 71 | display: flex; 72 | align-items: center; 73 | justify-content: center; 74 | font-size: 1.6rem; 75 | background-color: rgba($color-success, .3); 76 | width: 100%; 77 | height: 100%; 78 | } 79 | } 80 | } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/app/app.effects.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Actions, Effect } from '@ngrx/effects'; 3 | import { Store } from '@ngrx/store'; 4 | import { Observable } from 'rxjs/Observable'; 5 | import 'rxjs/add/operator/take'; 6 | import 'rxjs/add/operator/delay'; 7 | import 'rxjs/add/operator/mergeMap'; 8 | 9 | import { AppActions } from './app.actions'; 10 | 11 | import { Web3Actions } from '../core/web3/web3.actions'; 12 | import { PlayerResourcesActions } from '../core/player/resources/player-resources.actions'; 13 | 14 | @Injectable() 15 | export class AppEffects { 16 | 17 | constructor(public store: Store, 18 | private actions$: Actions) { 19 | } 20 | 21 | 22 | @Effect({dispatch: false}) setBuildings$ = this.actions$ 23 | .ofType(AppActions.Types.SET_BUILDINGS) 24 | .do(action => { 25 | this.store.select(s => s).take(1).subscribe(store => { 26 | let buildings = store.app.buildingsList; 27 | let blockNumber = store.web3.lastBlock; 28 | let goldRate: number = 0; 29 | let crystalRate: number = 0; 30 | let goldCapacity: number = 0; 31 | let crystalCapacity: number = 0; 32 | 33 | buildings.forEach(b => { 34 | if (b.active || b.endBlock < blockNumber) { 35 | goldRate += b.goldRate; 36 | crystalRate += b.crystalRate; 37 | goldCapacity += b.goldCapacity; 38 | crystalCapacity += b.crystalCapacity; 39 | return b; 40 | } 41 | if (Math.floor(b.id / 1000) > 1 && b.endBlock >= blockNumber) { 42 | let previousBuilding = buildings.find(building => building.id == b.previousLevelId) 43 | goldCapacity += previousBuilding.goldCapacity; 44 | crystalCapacity += previousBuilding.crystalCapacity; 45 | return previousBuilding; 46 | } 47 | return; 48 | }) 49 | this.store.dispatch(new PlayerResourcesActions.SetRatesAndCapacty( 50 | {goldRate, crystalRate, goldCapacity, crystalCapacity} 51 | )); 52 | }) 53 | }) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/app/shared/models/building.model.ts: -------------------------------------------------------------------------------- 1 | export interface BuildingMap { 2 | [buildingId: string]: Building; 3 | } 4 | 5 | export class Building { 6 | active: boolean; 7 | assetRequirements: any; 8 | attack: number; 9 | blocks: number; 10 | endBlock: number; 11 | crystalCapacity: number; 12 | crystalRate: number; 13 | defense: number; 14 | goldCapacity: number; 15 | goldRate: number; 16 | health: number; 17 | id: number; 18 | index: number; 19 | inQueue: boolean; 20 | inProgress: boolean; 21 | level: number; 22 | maxLevel: boolean; 23 | missingRequirements: any; 24 | name: string; 25 | owned: boolean; 26 | previousLevelId: number; 27 | price: number; 28 | nextLevelId: number; 29 | remainingBlocks: number; 30 | resource: string; 31 | startBlock: number; 32 | typeId: number; 33 | waiting: boolean; 34 | 35 | constructor(data: any = {}) { 36 | this.active = data.active; 37 | this.assetRequirements = data.assetRequirements || []; 38 | this.attack = data.attack; 39 | this.blocks = data.blocks; 40 | this.endBlock = data.endBlock; 41 | this.crystalCapacity = data.crystalCapacity; 42 | this.crystalRate = data.crystalRate; 43 | this.defense = data.defense; 44 | this.goldCapacity = data.goldCapacity; 45 | this.goldRate = data.goldRate; 46 | this.health = data.health; 47 | this.id = data.id; 48 | this.index = data.index; 49 | this.inQueue = !!data.endBlock; 50 | this.inProgress = data.inProgress; 51 | this.level = data.level; 52 | this.maxLevel = data.maxLevel; 53 | this.missingRequirements = data.missingRequirements || []; 54 | this.name = data.name; 55 | this.owned = this.active || this.inQueue; 56 | this.previousLevelId = data.previousLevelId; 57 | this.price = data.price; 58 | this.nextLevelId = data.nextLevelId; 59 | this.remainingBlocks = data.remainingBlocks; 60 | this.resource = data.resource; 61 | this.startBlock = data.startBlock; 62 | this.typeId = data.typeId; 63 | this.waiting = data.waiting; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /scripts/update-buildings.js: -------------------------------------------------------------------------------- 1 | const contracts = require('../data/contracts'); 2 | 3 | const BuildingsData = artifacts.require('./assets/buildings/BuildingsData.sol'); 4 | const AssetsRequirements = artifacts.require('./assets/buildings/AssetsRequirements.sol'); 5 | const buildingsMock = require('../data/production/buildings'); 6 | 7 | let activeAccount; 8 | 9 | module.exports = async (callback) => { 10 | 11 | const buildingsData = BuildingsData.at(contracts.BuildingsData); 12 | const assetsRequirements = AssetsRequirements.at(contracts.AssetsRequirements); 13 | 14 | web3.eth.getAccounts(async (err,res) => { 15 | activeAccount = res[0]; 16 | 17 | // Update buildings 18 | console.time('Updated buildings data'); 19 | for (let i = 0; i < buildingsMock.initialBuildings.length; i++) { 20 | const building = buildingsMock.initialBuildings[i]; 21 | if (i === (buildingsMock.initialBuildings.length - 1)) { 22 | await buildingsData.updateBuilding(building.id, building.name, building.stats, { from: activeAccount }); 23 | } else { 24 | buildingsData.updateBuilding(building.id, building.name, building.stats, { from: activeAccount }); 25 | } 26 | } 27 | console.timeEnd('Updated buildings data'); 28 | 29 | 30 | // Update buildings requirements 31 | console.time('Updated buildings requirements'); 32 | for (let i = 0; i < buildingsMock.initialBuildings.length; i++) { 33 | const building = buildingsMock.initialBuildings[i]; 34 | const oldRequirements = await assetsRequirements.getRequirements(building.id); 35 | for (let y = 0; y < oldRequirements.length; y++) { 36 | if (i === (buildingsMock.initialBuildings.length - 1) && y === (oldRequirements.length - 1)) { 37 | await assetsRequirements.updateAssetRequirement(building.id, oldRequirements[y], building.requirements[y]); 38 | } else { 39 | assetsRequirements.updateAssetRequirement(building.id, oldRequirements[y], building.requirements[y]); 40 | } 41 | } 42 | } 43 | console.timeEnd('Updated buildings requirements'); 44 | 45 | process.exit(0); 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /src/core/player/targets/player-targets.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerTargetsState } from './player-targets.state'; 2 | import { PlayerTargetsActions } from './player-targets.actions'; 3 | import { Status } from '../../shared/status.model'; 4 | 5 | export function playerTargetsReducer (state = initialPlayerTargetsState, action: PlayerTargetsActions.Actions) { 6 | switch (action.type) { 7 | case PlayerTargetsActions.Types.SELECT_TARGET: 8 | return Object.assign({}, state, { 9 | expandedTarget: action.payload 10 | }) 11 | 12 | case PlayerTargetsActions.Types.SET_TARGET_SUCCESS: 13 | return Object.assign({}, state, { 14 | status: new Status() 15 | }) 16 | 17 | case PlayerTargetsActions.Types.SET_TARGET_FAILURE: 18 | return Object.assign({}, state, { 19 | status: new Status({ 20 | loading: false, 21 | error: action.payload 22 | }) 23 | }) 24 | 25 | case PlayerTargetsActions.Types.SET_TARGETS: 26 | return Object.assign({}, state, { 27 | targets: action.payload, 28 | targetsNonce: state.targetsNonce + 1 29 | }) 30 | 31 | case PlayerTargetsActions.Types.GET_TARGETS: 32 | return Object.assign({}, state, { 33 | status: new Status({ 34 | error: null, 35 | loading: true 36 | }) 37 | }) 38 | 39 | case PlayerTargetsActions.Types.GET_TARGETS_SUCCESS: 40 | return Object.assign({}, state, { 41 | status: new Status() 42 | }) 43 | 44 | case PlayerTargetsActions.Types.GET_TARGETS_FAILURE: 45 | return Object.assign({}, state, { 46 | status: new Status({ 47 | loading: false, 48 | error: action.payload 49 | }) 50 | }) 51 | 52 | case PlayerTargetsActions.Types.SET_CURRENT_BLOCK: 53 | return Object.assign({}, state, { 54 | currentBlock: action.payload 55 | }) 56 | 57 | case PlayerTargetsActions.Types.SET_OLDEST_BLOCK: 58 | return Object.assign({}, state, { 59 | oldestBlock: action.payload 60 | }) 61 | 62 | default: 63 | return state; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/core/player/tokens/player-tokens.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../shared/util/type'; 3 | 4 | export namespace PlayerTokensActions { 5 | 6 | export const Types = { 7 | GET_BALANCES: type('[Player Tokens] Get Balances'), 8 | GET_ETH_BALANCE: type('[Player Tokens] Get Eth Balance'), 9 | GET_ETH_BALANCE_SUCCESS: type('[Player Tokens] Get Eth Balance Success'), 10 | GET_ETH_BALANCE_FAILURE: type('[Player Tokens] Get Eth Balance Failure'), 11 | GET_E11_BALANCE: type('[Player Tokens] Get e11 Balance'), 12 | GET_E11_BALANCE_SUCCESS: type('[Player Tokens] Get e11 Balance Success'), 13 | GET_E11_BALANCE_FAILURE: type('[Player Tokens] Get e11 Balance Failure'), 14 | } 15 | 16 | export class GetBalances implements Action { 17 | type = Types.GET_BALANCES; 18 | payload; 19 | 20 | constructor() { } 21 | } 22 | 23 | export class GetEthBalance implements Action { 24 | type = Types.GET_ETH_BALANCE; 25 | 26 | constructor(public payload: string) { } 27 | } 28 | 29 | export class GetEthBalanceSuccess implements Action { 30 | type = Types.GET_ETH_BALANCE_SUCCESS; 31 | 32 | constructor(public payload: number) { } 33 | } 34 | 35 | export class GetEthBalanceFailure implements Action { 36 | type = Types.GET_ETH_BALANCE_FAILURE; 37 | 38 | constructor(public payload: any) { } 39 | } 40 | 41 | export class GetE11Balance implements Action { 42 | type = Types.GET_E11_BALANCE 43 | 44 | constructor(public payload: string) { } 45 | } 46 | 47 | export class GetE11BalanceSuccess implements Action { 48 | type = Types.GET_E11_BALANCE_SUCCESS 49 | 50 | constructor(public payload: number) { } 51 | } 52 | 53 | export class GetE11BalanceFailure implements Action { 54 | type = Types.GET_E11_BALANCE_FAILURE 55 | 56 | constructor(public payload: any) { } 57 | } 58 | 59 | export type Actions 60 | = GetBalances 61 | | GetEthBalance 62 | | GetEthBalanceSuccess 63 | | GetEthBalanceFailure 64 | | GetE11Balance 65 | | GetE11BalanceSuccess 66 | | GetE11BalanceFailure 67 | } 68 | -------------------------------------------------------------------------------- /src/core/player/village/player-village.reducer.ts: -------------------------------------------------------------------------------- 1 | import { initialPlayerVillageState } from './player-village.state'; 2 | import { PlayerVillageActions } from './player-village.actions'; 3 | import { Status } from '../../shared/status.model'; 4 | 5 | export function playerVillageReducer (state = initialPlayerVillageState, action: PlayerVillageActions.Actions) { 6 | switch (action.type) { 7 | 8 | case PlayerVillageActions.Types.GET_VILLAGE_NAME: 9 | return Object.assign({}, state, { 10 | status: new Status({ 11 | error: null, 12 | loading: true 13 | }) 14 | }) 15 | 16 | case PlayerVillageActions.Types.GET_VILLAGE_NAME_SUCCESS: 17 | return Object.assign({}, state, { 18 | villageName: action.payload.substr(0, 25), // Max 25 characters 19 | status: new Status() 20 | }) 21 | 22 | case PlayerVillageActions.Types.GET_VILLAGE_NAME_FAILURE: 23 | case PlayerVillageActions.Types.GET_USER_POINTS_FAILURE: 24 | return Object.assign({}, state, { 25 | status: new Status({ error: action.payload.status.error }) 26 | }) 27 | 28 | case PlayerVillageActions.Types.GET_USER_POINTS: 29 | return Object.assign({}, state, { 30 | status: new Status({ 31 | error: null, 32 | loading: true 33 | }) 34 | }) 35 | 36 | case PlayerVillageActions.Types.GET_USER_POINTS_SUCCESS: 37 | return Object.assign({}, state, { 38 | points: action.payload, 39 | status: new Status() 40 | }) 41 | 42 | case PlayerVillageActions.Types.CREATE_VILLAGE: 43 | return Object.assign({}, state, { 44 | status: new Status({ 45 | error: null, 46 | loading: true 47 | }) 48 | }) 49 | 50 | case PlayerVillageActions.Types.CREATE_VILLAGE_SUCCESS: 51 | return Object.assign({}, state, { 52 | status: new Status() 53 | }) 54 | 55 | case PlayerVillageActions.Types.CREATE_VILLAGE_FAILURE: 56 | return Object.assign({}, state, { 57 | status: new Status({ error: action.payload.status.error }) 58 | }) 59 | 60 | default: 61 | return state; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/core/assets/units/data/units-data.effects.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Actions, Effect } from '@ngrx/effects'; 3 | import { Store } from '@ngrx/store'; 4 | import { Observable } from 'rxjs/Observable'; 5 | import 'rxjs/add/operator/take'; 6 | import 'rxjs/add/operator/delay'; 7 | import 'rxjs/add/operator/mergeMap'; 8 | 9 | 10 | import { AssetsUnitsDataActions } from './units-data.actions'; 11 | import { AssetsUnitsDataService } from './units-data.service'; 12 | import { DataUnit } from './data-unit.model'; 13 | 14 | import { ContractsService } from '../../../shared/contracts.service'; 15 | import { Status } from '../../../shared/status.model'; 16 | 17 | import { Web3Service } from '../../../web3/web3.service'; 18 | 19 | @Injectable() 20 | export class AssetsUnitsDataEffects { 21 | 22 | constructor(public store: Store, 23 | private actions$: Actions, 24 | private contractsService: ContractsService, 25 | private unitsDataService: AssetsUnitsDataService, 26 | private web3Service: Web3Service) { 27 | } 28 | 29 | @Effect() getUnitsData$ = this.actions$ 30 | .ofType(AssetsUnitsDataActions.Types.GET_UNITS_DATA) 31 | .switchMap((action: AssetsUnitsDataActions.GetUnitsData) => { 32 | return this.unitsDataService.getUnitsData() 33 | .map((unitsData) => { 34 | if (!unitsData[0] || unitsData[0].error || 35 | !unitsData[1] || unitsData[1].error) { 36 | return new AssetsUnitsDataActions.GetUnitsDataFailure({ 37 | error: unitsData[0].error || unitsData[1].error || 'unknown' 38 | }); 39 | } 40 | unitsData = unitsData[0].concat(unitsData[1]); 41 | let names = unitsData.shift(); // Shift first value (name) 42 | let ids = unitsData.shift(); // Shift second value (id) 43 | let units = {}; 44 | ids.forEach((id, i) => { 45 | id = id.toNumber(); 46 | let name = this.web3Service.web3.utils.hexToUtf8(names[i]); 47 | units[id] = new DataUnit(id, 48 | [name, ...unitsData.map(data => data[i])] 49 | ); 50 | }) 51 | return new AssetsUnitsDataActions.GetUnitsDataSuccess(units); 52 | }); 53 | }) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/core/assets/requirements/assets-requirements.effects.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Actions, Effect } from '@ngrx/effects'; 3 | import { Store } from '@ngrx/store'; 4 | import { Observable } from 'rxjs/Observable'; 5 | import 'rxjs/add/operator/take'; 6 | import 'rxjs/add/operator/delay'; 7 | import 'rxjs/add/operator/mergeMap'; 8 | 9 | import { AssetsRequirementsActions } from './assets-requirements.actions'; 10 | import { AssetsRequirementsService } from './assets-requirements.service'; 11 | 12 | import { AssetsBuildingsDataActions } from '../buildings/data/buildings-data.actions'; 13 | import { AssetsUnitsDataActions } from '../units/data/units-data.actions'; 14 | 15 | import { ContractsService } from '../../shared/contracts.service'; 16 | import { Web3Service } from '../../web3/web3.service'; 17 | 18 | 19 | @Injectable() 20 | export class AssetsRequirementsEffects { 21 | 22 | constructor(public store: Store, 23 | private actions$: Actions, 24 | private assetsRequirementsService: AssetsRequirementsService, 25 | private contractsService: ContractsService, 26 | private web3Service: Web3Service) { 27 | } 28 | 29 | @Effect() getBuildingsRequirements = this.actions$ 30 | .ofType(AssetsBuildingsDataActions.Types.GET_BUILDINGS_DATA_SUCCESS) 31 | .switchMap((action: AssetsBuildingsDataActions.GetBuildingsDataSuccess) => { 32 | let ids = Object.keys(action.payload); 33 | return this.assetsRequirementsService.getAssetsRequirements(ids) 34 | .map((requirements) => { 35 | return new AssetsRequirementsActions.GetRequirementsSuccess({ 36 | ids, 37 | requirements 38 | }); 39 | }); 40 | }) 41 | 42 | @Effect() getUnitRequirements = this.actions$ 43 | .ofType(AssetsUnitsDataActions.Types.GET_UNITS_DATA_SUCCESS) 44 | .switchMap((action: AssetsUnitsDataActions.GetUnitsDataSuccess) => { 45 | let ids = Object.keys(action.payload); 46 | return this.assetsRequirementsService.getAssetsRequirements(ids) 47 | .map((requirements) => { 48 | return new AssetsRequirementsActions.GetRequirementsSuccess({ 49 | ids, 50 | requirements 51 | }); 52 | }); 53 | }) 54 | 55 | 56 | 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/app/+assets/queue-navbar/queue-navbar.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

{{ 'ASSETS.NAVBAR.queue' | translate }}

5 | {{ 'ASSETS.NAVBAR.states.in-progress' | translate : { items: (itemsInQueue.length | largeNumber) } }}
6 | {{(remainingBlocks | largeNumber) || 0}} 7 | {{ 'APPWIDE.block' | translate }} 8 | {{ 'APPWIDE.blocks' | translate }} 9 | {{ 'ASSETS.NAVBAR.states.remaining' | translate : { time: (remainingBlocks | blockTime) } }} 10 | 11 |
12 |
13 |
21 |
24 |
25 |
30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 |
41 |
42 | -------------------------------------------------------------------------------- /src/core/player/resources/player-resources.actions.ts: -------------------------------------------------------------------------------- 1 | import { Action } from '@ngrx/store'; 2 | import { type } from '../../shared/util/type'; 3 | 4 | export namespace PlayerResourcesActions { 5 | 6 | export const Types = { 7 | GET_PLAYER_RESOURCES: type('[Player Resources] Get Player Resources'), 8 | GET_PLAYER_RESOURCES_SUCCESS: type('[Player Resources] Get Player Resources Success'), 9 | GET_PLAYER_RESOURCES_FAILURE: type('[Player Resources] Get Player Resources Failure'), 10 | GIVE_RESOURCES_TO_PLAYER: type('[Player Resources] Give Resources To Player'), 11 | SET_RATES_AND_CAPACITY: type('[Player Resources] Set Resources Rates and Capacity'), 12 | LOCK_PLAYER_RESOURCES: type('[Player Resources] Lock Player Resources'), 13 | UNLOCK_PLAYER_RESOURCES: type('[Player Resources] Unlock Player Resources') 14 | } 15 | 16 | export class GetPlayerResources implements Action { 17 | type = Types.GET_PLAYER_RESOURCES; 18 | payload; 19 | 20 | constructor() { } 21 | } 22 | 23 | export class GetPlayerResourcesSuccess implements Action { 24 | type = Types.GET_PLAYER_RESOURCES_SUCCESS; 25 | 26 | constructor(public payload: any[]) { } 27 | } 28 | 29 | export class GetPlayerResourcesFailure implements Action { 30 | type = Types.GET_PLAYER_RESOURCES_FAILURE; 31 | 32 | constructor(public payload: any) { } 33 | } 34 | 35 | export class GiveResourcesToPlayer implements Action { 36 | type = Types.GIVE_RESOURCES_TO_PLAYER; 37 | 38 | constructor(public payload: string) { } 39 | } 40 | 41 | export class SetRatesAndCapacty implements Action { 42 | type = Types.SET_RATES_AND_CAPACITY; 43 | 44 | constructor(public payload: any) { } 45 | } 46 | 47 | export class LockPlayerResources implements Action { 48 | type = Types.LOCK_PLAYER_RESOURCES; 49 | 50 | constructor(public payload: any) { } 51 | } 52 | 53 | export class UnlockPlayerResources implements Action { 54 | type = Types.UNLOCK_PLAYER_RESOURCES; 55 | 56 | constructor(public payload: any) { } 57 | } 58 | 59 | export type Actions 60 | = GetPlayerResources 61 | | GetPlayerResourcesSuccess 62 | | GetPlayerResourcesFailure 63 | | GiveResourcesToPlayer 64 | | SetRatesAndCapacty 65 | | LockPlayerResources 66 | | UnlockPlayerResources 67 | } 68 | -------------------------------------------------------------------------------- /src/core/player/targets/player-targets.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Store } from '@ngrx/store'; 3 | import { Observable } from 'rxjs'; 4 | import { of } from 'rxjs/observable/of'; 5 | import 'rxjs/add/observable/forkJoin'; 6 | import { fromPromise } from 'rxjs/observable/fromPromise'; 7 | 8 | import { ContractsService } from '../../shared/contracts.service'; 9 | import { Web3Service } from '../../web3/web3.service'; 10 | 11 | import { updateAndfilterUniqueTargets } from '../../../app/shared/util/helpers'; 12 | 13 | import { PlayerTarget } from './player-target.model'; 14 | 15 | @Injectable() 16 | export class PlayerTargetsService { 17 | 18 | constructor(private contractsService: ContractsService, 19 | private store: Store, 20 | private web3Service: Web3Service){ 21 | 22 | } 23 | 24 | getEvents(data) { 25 | return this.web3Service.getEvents( 26 | this.contractsService.PointsSystemInstance.PointsChanged, 27 | data.currentBlock, 28 | data.searchThreshold 29 | ).then((result: any) => { 30 | if (result.error) { 31 | return {error: result.error}; 32 | } 33 | result.data.reverse(); 34 | // address(user) -> number(block) 35 | let addressesObject = {}; 36 | result.data = result.data.filter(event => { 37 | if (!addressesObject[event.args.user] || addressesObject[event.args.user] < event.blockNumber) { 38 | addressesObject[event.args.user] = event.blockNumber; 39 | return true; 40 | } 41 | }); 42 | let newTargets = result.data.map(event => { 43 | return new PlayerTarget({ 44 | address: event.args.user, 45 | block: event.blockNumber, 46 | points: event.args.finalPoints.toNumber(), 47 | }); 48 | }) 49 | let addressBlockMap = {}; 50 | data.targets.forEach(target => addressBlockMap[target.address] = target.block); 51 | newTargets = newTargets.filter(target => { 52 | if (!addressBlockMap[target.address] || target.block > addressBlockMap[target.address]) { 53 | return true; 54 | } 55 | }); 56 | data.targets = updateAndfilterUniqueTargets(data.targets.concat(newTargets)); 57 | return data; 58 | } 59 | ) 60 | } 61 | 62 | } 63 | --------------------------------------------------------------------------------