Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion awesome_clicker/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

'author': "Odoo",
'website': "https://www.odoo.com/",
'category': 'Tutorials',
'category': 'Tutorials/AwesomeClicker',
'version': '0.1',
'application': True,
'installable': True,
Expand Down
7 changes: 7 additions & 0 deletions awesome_clicker/static/src/clicker_hook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";


export function useClicker() {
return useState(useService("awesome_clicker.clicker_service"))
}
29 changes: 29 additions & 0 deletions awesome_clicker/static/src/clicker_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const CURRENT_VERSION = 2.0;
export const migrations = [
{
fromVersion: 1.0,
toVersion: 2.0,
apply: (state) => {
state.trees.peachTree = {
price: 1500000,
level: 4,
fruit: "peach",
purchased: 0,
};
state.fruits.peach = 0;
}
}
];

export function migrate(localState) {
if (localState?.version < CURRENT_VERSION) {
for (const migration of migrations) {
if (localState.version === migration.fromVersion) {
migration.apply(localState);
localState.version = migration.toVersion;
}
}
localState.version = CURRENT_VERSION;
}
return localState;
}
145 changes: 145 additions & 0 deletions awesome_clicker/static/src/clicker_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { Reactive } from "@web/core/utils/reactive";
import { EventBus } from "@odoo/owl";
import { rewards } from "./clicker_reward";
import { choose } from "./utils";
import { CURRENT_VERSION } from "./clicker_migration";

export class ClickerModel extends Reactive {

constructor() {
super();
this.version = CURRENT_VERSION;
this.clicks = 0;
this.level = 0;
this.power = 1;
this.bots = {
clickbot: {
price: 1000,
increment: 10,
purchased: 0,
level: 1,
},
bigbot: {
price: 5000,
increment: 100,
purchased: 0,
level: 2,
}
};
this.trees = {
pearTree: {
price: 1000000,
level: 4,
purchased: 0,
fruit: "pear",
},
cherryTree: {
price: 1000000,
level: 4,
purchased: 0,
fruit: "cherry",
},
appleTree: {
price: 1000000,
level: 4,
purchased: 0,
fruit: "apple",
},
peachTree: {
price: 1500000,
level: 4,
fruit: "peach",
purchased: 0,
}
};
this.fruits = {
pear: 0,
cherry: 0,
apple: 0,
peach: 0,

}
this.bus = new EventBus();
}

ticks() {
for (const bot in this.bots) {
this.clicks += this.bots[bot].purchased * this.bots[bot].increment * this.power;
}
}

updateFruits() {
for (const tree in this.trees) {
this.fruits[this.trees[tree].fruit] += this.trees[tree].purchased;
}
}

increment(incr) {
this.clicks += incr;
if (this.level < 1 && this.clicks >= 1000) {
this.bus.trigger("MILESTONE_1k");
this.level++;
}
if (this.level < 2 && this.clicks >= 5000) {
this.bus.trigger("MILESTONE_5k");
this.level++;
}
if (this.level < 3 && this.clicks >= 100000) {
this.bus.trigger("MILESTONE_100k");
this.level++;
}
if (this.level < 4 && this.clicks >= 1000000) {
this.bus.trigger("MILESTONE_1M");
this.level++;
}
};

buyBot(bot) {
if (this.clicks < this.bots[bot].price){
return false;
}
this.clicks -= this.bots[bot].price;
this.bots[bot].purchased++;
};

buyPower() {
if (this.clicks < 50000){
return false;
}
this.power++;
this.clicks -= 50000;
}

buyTree(tree) {
if (this.clicks < 1000000){
return false;
}
this.trees[tree].purchased++;
this.clicks -= 1000000;
}

giveReward() {
const availableRewards = [];
for (const reward of rewards) {
if (reward.minLevel <= this.level || !reward.minLevel){
if (reward.maxLevel >= this.level || !reward.maxLevel){
availableRewards.push(reward);
}
}
}
const reward = choose(availableRewards);
this.bus.trigger("REWARD", reward);
}

toJSON() {
const json = Object.assign({}, this);
delete json["bus"];
return json;
}

static fromJSON(json) {
const clicker = new ClickerModel();
const clickerInstance = Object.assign(clicker, json);
return clickerInstance;
}
}
35 changes: 35 additions & 0 deletions awesome_clicker/static/src/clicker_provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { registry } from "@web/core/registry";

const commandProviderRegistry = registry.category("command_provider");

commandProviderRegistry.add("clicker", {
provide: (env, options) => {
return [
{
name: "Open Clicker Game",
action() {
env.services.action.doAction({
type: "ir.actions.client",
tag: "awesome_clicker.client_action",
target: "new",
name: "Clicker Game",
});

},
},
{
name: "Buy one ClickBot",
action() {
env.services["awesome_clicker.clicker_service"].buyBot("clickbot");
env.services.action.doAction({
type: "ir.actions.client",
tag: "awesome_clicker.client_action",
target: "new",
name: "Clicker Game",
});
}
}
];
},
});

24 changes: 24 additions & 0 deletions awesome_clicker/static/src/clicker_reward.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const rewards = [
{
description: "Get 1 click bot",
apply(clicker) {
clicker.bots.clickbot.purchased++;
},
maxLevel: 3,
},
{
description: "Get 1 big bot",
apply(clicker) {
clicker.bots.bigbot.purchased++;
},
minLevel: 3,
maxLevel: 4,
},
{
description: "Increase bot power!",
apply(clicker) {
clicker.power += 1;
},
minLevel: 3,
},
];
75 changes: 75 additions & 0 deletions awesome_clicker/static/src/clicker_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { registry } from "@web/core/registry";
import { ClickerModel } from "./clicker_model";
import { browser } from "@web/core/browser/browser";
import { migrate } from "./clicker_migration";


const clickerService = {
dependencies: ["action", "effect", "notification"],
start(env, services) {
const localState = migrate(JSON.parse(browser.localStorage.getItem("clickerState")));
const model = localState ? ClickerModel.fromJSON(localState): new ClickerModel();

setInterval(() => model.ticks(), 10000);
setInterval(() => model.updateFruits(), 30000);

setInterval(() => {
browser.localStorage.setItem("clickerState", JSON.stringify(model))
}, 10000);

const bus = model.bus;
bus.addEventListener("MILESTONE_1k", () => {
services.effect.add({
type: "rainbow_man",
message: "Milestone reached! You can now buy ClickBots",
});
});
bus.addEventListener("MILESTONE_5k", () => {
services.effect.add({
type: "rainbow_man",
message: "Milestone reached! You can now buy BigBots",
});
});
bus.addEventListener("MILESTONE_100k", () => {
services.effect.add({
type: "rainbow_man",
message: "Milestone reached! You can now buy Powers",
});
});
bus.addEventListener("MILESTONE_1M", () => {
services.effect.add({
type: "rainbow_man",
message: "Milestone reached! You can now buy Trees",
});
});
bus.addEventListener("REWARD", (ev) => {
const reward = ev.detail;
const closeNotification = services.notification.add(
`Congrats, you won a reward: "${reward.description}"`,
{
type: "success",
sticky: true,
buttons: [
{
name: "Collect",
onClick: () => {
reward.apply(model);
closeNotification();
services.action.doAction({
type: "ir.actions.client",
tag: "awesome_clicker.client_action",
target: "new",
name: "Clicker Game"
});
},
},
],
}
);
})

return model;
}
}

registry.category("services").add("awesome_clicker.clicker_service", clickerService);
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Component, useExternalListener } from "@odoo/owl";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { useClicker } from "../clicker_hook";
import { ClickerValue } from "../clicker_value/clicker_value";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";

export class ClickerSystray extends Component {
static template = "awesome_clicker.ClickerSystray";
static components = { ClickerValue, Dropdown, DropdownItem };

setup() {
this.client_action = useService("action");
this.clicker = useClicker();
useExternalListener(document.body, "click", this.incrementCounter, true);
}

incrementCounter(){
this.clicker.increment(1);
}

openClientAction() {
this.client_action.doAction({
type: "ir.actions.client",
tag: "awesome_clicker.client_action",
target: "new",
name: "Clicker Game"
});
}

get numberTrees() {
let numberOfTrees = 0;
for (const tree in this.clicker.trees) {
numberOfTrees += this.clicker.trees[tree].purchased;
}
return numberOfTrees;
}

get numberFruits() {
let numberOfFruits = 0;
for (const fruit in this.clicker.fruits) {
numberOfFruits += this.clicker.fruits[fruit];
}
return numberOfFruits;
}

}

export const systrayItem = {
Component: ClickerSystray,
};

registry.category("systray").add("awesome_clicker.ClickerSystray", systrayItem, { sequence: 1000 });
Loading