Skip to content

Commit

Permalink
add betting prompt [#2]
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzdanilo committed Jun 3, 2021
1 parent 6764a3e commit 7fcd1a8
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 0 deletions.
26 changes: 26 additions & 0 deletions ecs/Banca.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
ActionButton,
BoxShape,
Entity,
Material,
OnPointerDown,
Texture,
Transform,
TransformConstructorArgs,
} from 'decentraland-ecs';
import TicketPrompt from './TicketPrompt';

export default class Banca extends Entity {
constructor(transformArgs: TransformConstructorArgs) {
super('Banca');
this.addComponent(new Transform(transformArgs));
this.addComponent(new BoxShape());

const material = new Material();
material.albedoTexture = new Texture('https://dummyimage.com/100x100/ffd700/000000.png&text=BET');
this.addComponent(material);

this.addComponent(new OnPointerDown(() => TicketPrompt.show(),
{ hoverText: 'bet', showFeedback: true, button: ActionButton.POINTER }));
}
}
4 changes: 4 additions & 0 deletions ecs/SceneManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
IEngine,
ISystem,
MessageBus,
Vector3,
} from 'decentraland-ecs';
import Banca from './Banca';
import Bicho, { BichoType } from './Bicho';
import getUserAddress from './web3/getUserAddress';
import getUserBichos from './web3/getUserBichos';
Expand Down Expand Up @@ -43,6 +45,8 @@ export default class SceneManager implements ISystem {
this.address = address;
bichos?.forEach((type) => this.bus.emit('bicho', { address, type } as BichoEvent));
});

this.engine.addEntity(new Banca({ position: new Vector3(8, 1, 8) }));
}

deactivate() {
Expand Down
139 changes: 139 additions & 0 deletions ecs/TicketPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/// <reference path="assets.d.ts"/>
import {
ButtonStyles,
CustomPrompt,
CustomPromptButton,
CustomPromptCheckBox,
CustomPromptText,
LoadingIcon,
PromptStyles,
} from '@dcl/ui-scene-utils';
import { DecentralandInterface, Entity } from 'decentraland-ecs';
import { BichoType } from './Bicho';
import image from './images/ticket.jpg';
import getBichoContract from './web3/getBichoContract';
import getSigner from './web3/getSigner';

declare const dcl: DecentralandInterface;

const IMAGE_SCALE = 2 / 3;
const IMAGE_WIDTH = 580 - 13 - 13;
const IMAGE_HEIGHT = 864 - 104 - 31;

const COLUMN_COUNT = 5;
const COLUMN_WIDTH = IMAGE_WIDTH / COLUMN_COUNT - 1;
const COLUMN_HEIGHT = IMAGE_HEIGHT / COLUMN_COUNT + 1;

const BAR_HEIGHT = 64;
const CONTENT_Y = BAR_HEIGHT / 2;
const BAR_Y = -(IMAGE_HEIGHT * IMAGE_SCALE + 16) / 2;

enum State {
Bet,
Waiting,
Result,
}

interface CustomPromptElement extends Entity {
hide(): void;
show(): void;
}

class TicketPrompt extends CustomPrompt {
protected bichos: CustomPromptCheckBox[];

protected submitButton: CustomPromptButton;

protected result: CustomPromptText;

protected state: State;

protected groups: { [S in State]?: CustomPromptElement[] } = {};

constructor() {
super(PromptStyles.LIGHT,
IMAGE_WIDTH * IMAGE_SCALE + 48, IMAGE_HEIGHT * IMAGE_SCALE + BAR_HEIGHT + 48);

this.result = this.addText(null, 0, CONTENT_Y);
this.groups[State.Result] = [this.result,
this.addButton('OK', 0, BAR_Y, () => this.hide(), ButtonStyles.RED)];

const loading = new LoadingIcon(null, 0, 0);
this.elements.push(loading);
this.groups[State.Waiting] = [loading];

const ticket = this.addIcon(image, 0, CONTENT_Y,
IMAGE_WIDTH * IMAGE_SCALE, IMAGE_HEIGHT * IMAGE_SCALE, {
sourceLeft: 13, sourceTop: 104, sourceWidth: IMAGE_WIDTH, sourceHeight: IMAGE_HEIGHT,
});
const cancelButton = this.addButton('Cancel', 100, BAR_Y, () => this.hide(), ButtonStyles.F);
this.submitButton = this.addButton('Bet', -100, BAR_Y, () => this.submit(), ButtonStyles.RED);
this.bichos = [...Array(BichoType.COUNT)].map((_: any, i) => {
const x = i % COLUMN_COUNT;
const y = Math.floor(i / COLUMN_COUNT);
const xOffset = (x - (COLUMN_COUNT - 1) / 2) * IMAGE_SCALE * COLUMN_WIDTH;
const yOffset = ((COLUMN_COUNT - 1) / 2 - y) * IMAGE_SCALE * COLUMN_HEIGHT + CONTENT_Y;
return this.addCheckbox(
null,
xOffset - 38 * IMAGE_SCALE,
yOffset - 33 * IMAGE_SCALE,
() => {
if (!dcl.DEBUG) this.bichos.forEach((checkbox, j) => i !== j && checkbox.uncheck());
this.submitButton.enable();
},
() => this.submitButton.grayOut(),
);
});
this.groups[State.Bet] = [ticket, cancelButton, this.submitButton, ...this.bichos];

this.hide();
}

reset() {
this.submitButton.grayOut();
this.bichos.forEach((checkbox) => checkbox.uncheck());
this.result.text.value = null;
this.state = State.Bet;
}

hide() {
super.hide();
this.reset();
}

show() {
this.background.visible = true;
Object.entries(this.groups).forEach(([key, entities]) => {
const visible = Number(key) === this.state;
entities.forEach((entity) => (visible ? entity.show() : entity.hide()));
});
}

async submit() {
try {
this.setState(State.Waiting);
const [contract, signer] = await Promise.all([getBichoContract(), getSigner()]);
const writableContract = contract.connect(signer);
let nonce = await signer.getTransactionCount();
await Promise.all(this.bichos.map(async (checkbox, i) => {
if (!checkbox.checked) return;
await writableContract.bet(i, { nonce: ++nonce });
}));
this.hide();
} catch ({ code, message }) {
if (code === 4001) {
this.hide();
} else {
this.result.text.value = `ERROR\n\n${message ?? ''}`;
this.setState(State.Result);
}
}
}

setState(state: State) {
this.state = state;
this.show();
}
}

export default new TicketPrompt();
Binary file added ecs/images/ticket.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions ecs/web3/getSigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { JsonRpcSigner } from '@ethersproject/providers';
import getProvider from './getProvider';
import getUserAddress from './getUserAddress';

let signer: Promise<JsonRpcSigner>;

const getSigner = async () => {
const [address, provider] = await Promise.all([getUserAddress(), getProvider()]);
return address && provider.getSigner(address);
};

export default async () => {
signer ??= getSigner();
return signer;
};
3 changes: 3 additions & 0 deletions webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ function config(_: any, { mode = 'production' }): Configuration {
Fonts: ['decentraland-ecs', 'Fonts'],
GLTFShape: ['decentraland-ecs', 'GLTFShape'],
Input: ['decentraland-ecs', 'Input'],
OnChanged: ['decentraland-ecs', 'OnChanged'],
OnClick: ['decentraland-ecs', 'OnClick'],
OnPointerDown: ['decentraland-ecs', 'OnPointerDown'],
OnTextSubmit: ['decentraland-ecs', 'OnTextSubmit'],
Quaternion: ['decentraland-ecs', 'Quaternion'],
Texture: ['decentraland-ecs', 'Texture'],
Transform: ['decentraland-ecs', 'Transform'],
UICanvas: ['decentraland-ecs', 'UICanvas'],
UIContainerRect: ['decentraland-ecs', 'UIContainerRect'],
UIImage: ['decentraland-ecs', 'UIImage'],
UIInputText: ['decentraland-ecs', 'UIInputText'],
UIText: ['decentraland-ecs', 'UIText'],
Vector3: ['decentraland-ecs', 'Vector3'],
engine: ['decentraland-ecs', 'engine'],
Expand Down

0 comments on commit 7fcd1a8

Please sign in to comment.