diff --git a/content/out_0.json b/content/out_0.json index ace8d46..e8d4e4a 100755 --- a/content/out_0.json +++ b/content/out_0.json @@ -1 +1 @@ -{"sprites":[{"name":"card_bg","tags":[{"from":0,"to":0,"name":"idle"}],"packs":[{"frame":{"x":0,"y":0,"w":140,"h":250},"packed":{"x":0,"y":0,"w":140,"h":250}}]},{"name":"card_underline","tags":[{"from":0,"to":0,"name":"idle"},{"from":1,"to":3,"name":"open"}],"packs":[{"frame":{"x":0,"y":0,"w":20,"h":200},"packed":{"x":140,"y":0,"w":20,"h":200}},{"frame":{"x":0,"y":0,"w":20,"h":200},"packed":{"x":160,"y":0,"w":20,"h":200}},{"frame":{"x":0,"y":0,"w":20,"h":200},"packed":{"x":180,"y":0,"w":20,"h":200}},{"frame":{"x":0,"y":0,"w":20,"h":200},"packed":{"x":200,"y":0,"w":20,"h":200}}]},{"name":"palette","tags":[{"from":0,"to":0,"name":"1"},{"from":1,"to":1,"name":"2"},{"from":2,"to":2,"name":"3"},{"from":3,"to":3,"name":"4"},{"from":4,"to":4,"name":"5"}],"packs":[{"frame":{"x":0,"y":0,"w":8,"h":8},"packed":{"x":248,"y":340,"w":8,"h":8}},{"frame":{"x":0,"y":0,"w":8,"h":8},"packed":{"x":256,"y":340,"w":8,"h":8}},{"frame":{"x":0,"y":0,"w":8,"h":8},"packed":{"x":264,"y":340,"w":8,"h":8}},{"frame":{"x":0,"y":0,"w":8,"h":8},"packed":{"x":272,"y":340,"w":8,"h":8}},{"frame":{"x":0,"y":0,"w":8,"h":8},"packed":{"x":280,"y":340,"w":8,"h":8}}]},{"name":"title_bg","tags":[{"from":0,"to":0,"name":"idle"}],"packs":[{"frame":{"x":0,"y":0,"w":248,"h":40},"packed":{"x":0,"y":340,"w":248,"h":40}}]},{"name":"transition","tags":[{"from":0,"to":5,"name":"cover"}],"packs":[{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":140,"y":200,"w":80,"h":45}},{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":0,"y":250,"w":80,"h":45}},{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":80,"y":250,"w":80,"h":45}},{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":160,"y":250,"w":80,"h":45}},{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":0,"y":295,"w":80,"h":45}},{"frame":{"x":0,"y":0,"w":80,"h":45},"packed":{"x":80,"y":295,"w":80,"h":45}}]}]} \ No newline at end of file +{"sprites":[{"name":"main_card_bg","tags":[{"from":0,"to":0,"name":"idle"}],"packs":[{"frame":{"x":0,"y":0,"w":420,"h":520},"packed":{"x":0,"y":0,"w":420,"h":520}}]}]} \ No newline at end of file diff --git a/content/out_0.png b/content/out_0.png index e064be4..be82b30 100755 Binary files a/content/out_0.png and b/content/out_0.png differ diff --git a/content/sprites/card_bg.ase b/content/sprites/card_bg.ase deleted file mode 100755 index 9ef54e3..0000000 Binary files a/content/sprites/card_bg.ase and /dev/null differ diff --git a/content/sprites/card_underline.ase b/content/sprites/card_underline.ase deleted file mode 100755 index c9529a1..0000000 Binary files a/content/sprites/card_underline.ase and /dev/null differ diff --git a/content/sprites/main_card_bg.ase b/content/sprites/main_card_bg.ase new file mode 100755 index 0000000..e67122d Binary files /dev/null and b/content/sprites/main_card_bg.ase differ diff --git a/content/sprites/palette.ase b/content/sprites/palette.ase deleted file mode 100755 index 20f7626..0000000 Binary files a/content/sprites/palette.ase and /dev/null differ diff --git a/content/sprites/title_bg.ase b/content/sprites/title_bg.ase deleted file mode 100755 index e9c3448..0000000 Binary files a/content/sprites/title_bg.ase and /dev/null differ diff --git a/content/sprites/transition.ase b/content/sprites/transition.ase deleted file mode 100755 index 0efdb9c..0000000 Binary files a/content/sprites/transition.ase and /dev/null differ diff --git a/screens/design.ase b/screens/design.ase new file mode 100755 index 0000000..066ce9c Binary files /dev/null and b/screens/design.ase differ diff --git a/screens/navigation.ase b/screens/navigation.ase index ea412eb..845ffe5 100755 Binary files a/screens/navigation.ase and b/screens/navigation.ase differ diff --git a/src/anim.ts b/src/anim.ts new file mode 100644 index 0000000..d7e2d59 --- /dev/null +++ b/src/anim.ts @@ -0,0 +1,56 @@ +import { TextureFilter, TextureSampler } from 'blah' +import { Color } from 'blah' +import { Rect, Vec2, Mat3x2 } from 'blah' +import { Time, App, batch, Batch, Target } from 'blah' + +import Content from './content' + +import { Play } from './play' + + +export type AnimData = { + name: string +} + +export class Anim extends Play { + + get data() { + return this._data as AnimData + } + + get sprite() { + return Content.find_sprite(this.data.name) + } + + _animation: string = 'idle' + get animation() { + return this.sprite.get(this._animation) + } + + _frame: number = 0 + + get frame() { + return this.animation?.frames[this._frame] + + } + + get subtexture() { + return this.frame?.image + } + + get duration() { + return this.frame?.duration + } + + + _draw(batch: Batch) { + + if (!this.subtexture) { + return + } + + + batch.stex(this.subtexture, this.position, Color.white) + + } +} diff --git a/src/game.ts b/src/game.ts index 11032dd..ccbd86e 100644 --- a/src/game.ts +++ b/src/game.ts @@ -13,6 +13,10 @@ import { InfiniteScrollableList } from './scrollable' import { bg1, link_color, Play, PlayType} from './play' +import { Anim } from './anim' + +import { SolitairePlay } from './solitaire' + type RectData = { w: number, h: number, @@ -30,7 +34,7 @@ class RectView extends Play { } } -class Background extends Play { +export class Background extends Play { _init() { this.make(RectView, Vec2.make(0, 0), { @@ -72,6 +76,7 @@ class MainTitle extends Play { type ClickableData = { + debug?: true, rect: Rect, on_hover?: () => void, on_hover_end?: () => void, @@ -126,6 +131,15 @@ class Clickable extends Play { }) } + _draw() { + batch.push_matrix(Mat3x2.create_translation(this.position)) + this.g_position = Vec2.transform(Vec2.zero, batch.m_matrix) + if (this.data.debug) { + batch.rect(Rect.make(0, 0, this.width, this.height), Color.hex(0x00ff00)) + } + batch.pop_matrix() + } + } type MainSideBarItemData = { @@ -194,11 +208,11 @@ class MainSideBar extends Play { _ = this._make(MainSideBarItem, Vec2.make(0, 0), { icon: 'how to play', next: HowtoPlay }) tabs.push(_) - _ = this._make(MainSideBarItem, Vec2.make(0, _.height), { icon: 'settings', next: HowtoPlay }) + _ = this._make(MainSideBarItem, Vec2.make(0, _.height), { icon: 'settings', next: Settings }) tabs.push(_) _ = this._make(MainSideBarItem, Vec2.make(0, _.height * 2), { icon: 'statistics', next: Statistics }) tabs.push(_) - _ = this._make(MainSideBarItem, Vec2.make(0, _.height * 3), { icon: 'about', next: HowtoPlay }) + _ = this._make(MainSideBarItem, Vec2.make(0, _.height * 3), { icon: 'about', next: About }) tabs.push(_) this.make(Tabs, Vec2.make(4, 4), { @@ -209,7 +223,7 @@ class MainSideBar extends Play { } } -class MainMenu extends Play { +export class MainMenu extends Play { _init() { this.make(Background, Vec2.zero, undefined) @@ -218,6 +232,64 @@ class MainMenu extends Play { this.make(MainSideBar, Vec2.make(1320, 100), {}) + this.make(MainCards, Vec2.make(80, 260), {}) + + } +} + + +class MainCards extends Play { + + + _init() { + let w = 380 + this.make(MainCard, Vec2.make(0, 0), { + text: 'solitaire' + }) + this.make(MainCard, Vec2.make(w, 0), { + text: 'freecell' + }) + this.make(MainCard, Vec2.make(w * 2, 0), { + text: 'spider' + }) + } + +} + +type MainCardData = { + text: string +} + +class MainCard extends Play { + + get data() { + return this._data as MainCardData + } + + _init() { + + this.make(Anim, Vec2.make(0, 0), { + name: 'main_card_bg' + }) + + let text = this.make(Text, Vec2.make(-450, 200), { + text: this.data.text, + rotation: - Math.PI * 0.5, + color: Color.black + }) + + this.make(Clickable, Vec2.make(60, 64), { + rect: Rect.make(0, 0, 300, 420), + on_click() { + scene_transition.next(SolitairePlay) + }, + on_hover() { + text.color = Color.red + }, + on_hover_end() { + text.color = Color.black + } + }) } } @@ -485,6 +557,64 @@ class ScrollableListLongContent extends Play { } + +class Settings extends Play { + _init() { + + this.make(Background, Vec2.zero, undefined) + + let self = this + this.make(Navigation, Vec2.zero, { + route: 'settings', + on_back() { + scene_transition.next(MainMenu) + } + }) + + + let content = this._make(RectView, Vec2.make(0, 0), { + w: 100, + h: 100 + }) + + this.make(ScrollableContent, Vec2.make(20, 120), { + w: 1880, + h: 940, + content + }) + + + } +} +class About extends Play { + _init() { + + this.make(Background, Vec2.zero, undefined) + + let self = this + this.make(Navigation, Vec2.zero, { + route: 'about', + on_back() { + scene_transition.next(MainMenu) + } + }) + + + let content = this._make(LongHyperText, Vec2.make(0, 0), { + width: 1880 - 80, + content: howtos['about'] + }) + + this.make(ScrollableContent, Vec2.make(20, 120), { + w: 1880, + h: 940, + content + }) + + + } +} + class HowtoPlay extends Play { _init() { @@ -523,7 +653,7 @@ class HowtoPlay extends Play { let content = this._make(LongHyperText, Vec2.make(0, 0), { width: 1880 - 80, - content: howtos['about'] + content: howtos['solitaire'] }) this.make(ScrollableContent, Vec2.make(20, 120), { @@ -669,7 +799,7 @@ type NavigationData = { on_back: () => void } -class Navigation extends Play { +export class Navigation extends Play { get data() { return this._data as NavigationData @@ -726,6 +856,7 @@ type TextData = { text: string, center?: true, color?: Color + rotation?: number } export class Text extends Play { @@ -734,6 +865,10 @@ export class Text extends Play { return this._data as TextData } + get rotation() { + return this.data.rotation ?? 0 + } + get origin() { return this.data.center ? Vec2.make(this.width / 2, 0) : Vec2.zero } @@ -768,7 +903,7 @@ export class Text extends Play { _draw(batch: Batch) { - batch.push_matrix(Mat3x2.create_transform(Vec2.zero, this.origin, Vec2.one, 0)) + batch.push_matrix(Mat3x2.create_transform(Vec2.zero, this.origin, Vec2.one, this.rotation)) this.g_position = Vec2.transform(this.position, batch.m_matrix) batch.str_j(this.font, this.text, this.position, this.justify, this.size, this.color) @@ -1130,7 +1265,7 @@ class SceneTransition extends Play { } } -let scene_transition: SceneTransition +export let scene_transition: SceneTransition export default class Game extends Play { diff --git a/src/howtos.ts b/src/howtos.ts index 4fd80aa..8284abc 100644 --- a/src/howtos.ts +++ b/src/howtos.ts @@ -1,6 +1,46 @@ let spider = `` -let solitaire = `` +let solitaire = ` +Solitaire is played with a standard 52-card deck. +A tableu of 7 piles of cards are laid, first pile contains 1 card, second pile contains 2 cards and so on. The topmost card of each pile is turned face up, the cards behind are turned face down. +The remaining cards form the stock and are placed facedown at the upper left. + +The four foundations are built up by suit from Ace to King. +The tableu piles can be built down by alternate colors. +Every face-up card in a partial pile, or a complete pile, can be moved, as a unit, to another tableu pile on the basis of its highest card. +Any empty piles can be filled with a King, or a pile of cards with a King. + +The aim of the game is to build up four stacks of cards from Ace to King for each suit, on one of the four foundations. + +There are different ways of dealing the stock cards to the waste depending on these two settings. + +Turning cards +- Three cards: Turning three cards at once to the waste +- One card: Turning one card at once to the waste + +Turning limit +- No limit: no limit on passes through the deck. +- 3 passes: 3 passes through the deck. +- 1 pass: 1 pass through the deck. + + +- If all face up cards in a tableu is moved, the topmost back facing card is turned over. +- Cards in waste can be moved to a tableu or a foundation. +- The topmost card in a foundation can be moved back to a tableu. +- If the stock is empty and there are cards in the waste, waste cards can be recycled back to stock if pass through the deck is allowed according to turning limit. +- Moves can be undo with the undo button. + + +The scoring system is: + +- waste to tableu: 5 points +- waste to foundation: 10 points +- tableu to foundation: 10 points +- turn over tableu card: 5 points +- foundation to tableu: -15 points +- recycle waste: -70 points +- undo a move: -30 points +` let freecell = `` diff --git a/src/solitaire.ts b/src/solitaire.ts new file mode 100644 index 0000000..cae6302 --- /dev/null +++ b/src/solitaire.ts @@ -0,0 +1,38 @@ +import { TextureFilter, TextureSampler } from 'blah' +import { Color } from 'blah' +import { Rect, Vec2, Mat3x2 } from 'blah' +import { Time, App, batch, Batch, Target } from 'blah' + +import Content from './content' +import Input, { Hooks, EventPosition, DragEvent } from './input' +import { howtos } from './howtos' +import { Transition, transition } from './transition' + +import { rmap, ease, lerp, appr } from './lerp' +import { InfiniteScrollableList } from './scrollable' + +import { bg1, link_color, Play, PlayType} from './play' + +import { Anim } from './anim' + +import { Background, MainMenu, Navigation } from './game' +import { scene_transition }from './game' + +export class SolitairePlay extends Play { + + _init() { + + + this.make(Background, Vec2.zero, undefined) + + this.make(Navigation, Vec2.zero, { + route: 'solitaire', + on_back() { + scene_transition.next(MainMenu) + } + }) + + + } + +}