diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..2ad291b Binary files /dev/null and b/favicon.ico differ diff --git a/index.html b/index.html index e4f19cb..7665627 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,10 @@ + DND Mapper - - - + + + -
+ +
+ + + diff --git a/res/Zepha.ttf b/res/Zepha.ttf new file mode 100644 index 0000000..bb34b15 Binary files /dev/null and b/res/Zepha.ttf differ diff --git a/res/_assets.txt b/res/_assets.txt new file mode 100644 index 0000000..5a983ed --- /dev/null +++ b/res/_assets.txt @@ -0,0 +1,19 @@ +cursor +grid_tile + +FOLDERPREFIX ui ui_ +ui/button_grid +ui/button_side_menu 21 18 +ui/history_manipulation 39 18 +ui/mode_switch 39 18 +ui/quick_selector +ui/text_box 100 6 +ui/text_input 100 6 +ui/sidebar_bg 68 21 +ui/sidebar_cursor +ui/sidebar_overlay + +FOLDERPREFIX tileset tileset_ +tileset/0 +tileset/1 +tileset/2 diff --git a/res/dice.png b/res/dice.png new file mode 100644 index 0000000..f25a1b9 Binary files /dev/null and b/res/dice.png differ diff --git a/res/favicon.png b/res/favicon.png new file mode 100644 index 0000000..c6b3346 Binary files /dev/null and b/res/favicon.png differ diff --git a/res/font.zip b/res/font.zip new file mode 100644 index 0000000..e2ba4b2 Binary files /dev/null and b/res/font.zip differ diff --git a/res/font/font0.fnt b/res/font/font0.fnt new file mode 100644 index 0000000..e600dfa --- /dev/null +++ b/res/font/font0.fnt @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/font/font0.png b/res/font/font0.png new file mode 100644 index 0000000..d95d972 Binary files /dev/null and b/res/font/font0.png differ diff --git a/res/font/font1.fnt b/res/font/font1.fnt new file mode 100644 index 0000000..4c889cf --- /dev/null +++ b/res/font/font1.fnt @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/font/font1.png b/res/font/font1.png new file mode 100644 index 0000000..054a74a Binary files /dev/null and b/res/font/font1.png differ diff --git a/res/font/font2.fnt b/res/font/font2.fnt new file mode 100644 index 0000000..8c4b936 --- /dev/null +++ b/res/font/font2.fnt @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/font/font2.png b/res/font/font2.png new file mode 100644 index 0000000..4e96ced Binary files /dev/null and b/res/font/font2.png differ diff --git a/res/grid.png b/res/grid.png deleted file mode 100644 index 5fdad69..0000000 Binary files a/res/grid.png and /dev/null differ diff --git a/res/grid_tile.png b/res/grid_tile.png new file mode 100644 index 0000000..6ca6a35 Binary files /dev/null and b/res/grid_tile.png differ diff --git a/res/logo.png b/res/logo.png new file mode 100644 index 0000000..bb44f3d Binary files /dev/null and b/res/logo.png differ diff --git a/res/player.png b/res/player.png deleted file mode 100644 index 283fe67..0000000 Binary files a/res/player.png and /dev/null differ diff --git a/res/splash.png b/res/splash.png new file mode 100644 index 0000000..5121dc2 Binary files /dev/null and b/res/splash.png differ diff --git a/res/splash.xcf b/res/splash.xcf new file mode 100644 index 0000000..50c5432 Binary files /dev/null and b/res/splash.xcf differ diff --git a/res/tileset_1.png b/res/tileset/0.png similarity index 100% rename from res/tileset_1.png rename to res/tileset/0.png diff --git a/res/tileset_1.xcf b/res/tileset/0.xcf similarity index 100% rename from res/tileset_1.xcf rename to res/tileset/0.xcf diff --git a/res/tileset_3.attrib b/res/tileset/floor_grass.attrib similarity index 100% rename from res/tileset_3.attrib rename to res/tileset/floor_grass.attrib diff --git a/res/tileset/floor_grass.png b/res/tileset/floor_grass.png new file mode 100644 index 0000000..1b975f6 Binary files /dev/null and b/res/tileset/floor_grass.png differ diff --git a/res/tileset/ground_dirt.png b/res/tileset/ground_dirt.png new file mode 100644 index 0000000..57b1b66 Binary files /dev/null and b/res/tileset/ground_dirt.png differ diff --git a/res/tileset/ground_dirt.xcf b/res/tileset/ground_dirt.xcf new file mode 100644 index 0000000..54bca7a Binary files /dev/null and b/res/tileset/ground_dirt.xcf differ diff --git a/res/tileset/ground_grass.png b/res/tileset/ground_grass.png new file mode 100644 index 0000000..a3fdbef Binary files /dev/null and b/res/tileset/ground_grass.png differ diff --git a/res/tileset/ground_grass.xcf b/res/tileset/ground_grass.xcf new file mode 100644 index 0000000..27f45ca Binary files /dev/null and b/res/tileset/ground_grass.xcf differ diff --git a/res/tileset/wall_stone.xcf b/res/tileset/wall_stone.xcf new file mode 100644 index 0000000..010d740 Binary files /dev/null and b/res/tileset/wall_stone.xcf differ diff --git a/res/tileset/wall_wood.png b/res/tileset/wall_wood.png new file mode 100644 index 0000000..0ad0e42 Binary files /dev/null and b/res/tileset/wall_wood.png differ diff --git a/res/tileset/wall_wood.xcf b/res/tileset/wall_wood.xcf new file mode 100644 index 0000000..76a3d83 Binary files /dev/null and b/res/tileset/wall_wood.xcf differ diff --git a/res/tileset_2.png b/res/tileset_2.png deleted file mode 100644 index e5e2efa..0000000 Binary files a/res/tileset_2.png and /dev/null differ diff --git a/res/tileset_2.xcf b/res/tileset_2.xcf deleted file mode 100644 index 0394ebd..0000000 Binary files a/res/tileset_2.xcf and /dev/null differ diff --git a/res/tileset_3.png b/res/tileset_3.png deleted file mode 100644 index 5006fc8..0000000 Binary files a/res/tileset_3.png and /dev/null differ diff --git a/res/token/armor_1.png b/res/token/armor_1.png new file mode 100644 index 0000000..ed54d6a Binary files /dev/null and b/res/token/armor_1.png differ diff --git a/res/token/bones.png b/res/token/bones.png new file mode 100644 index 0000000..60a1489 Binary files /dev/null and b/res/token/bones.png differ diff --git a/res/token/cadin_1.png b/res/token/cadin_1.png new file mode 100644 index 0000000..2009e55 Binary files /dev/null and b/res/token/cadin_1.png differ diff --git a/res/token/cadin_2.png b/res/token/cadin_2.png new file mode 100644 index 0000000..13d9fc7 Binary files /dev/null and b/res/token/cadin_2.png differ diff --git a/res/token/cadin_3.png b/res/token/cadin_3.png new file mode 100644 index 0000000..d4471e9 Binary files /dev/null and b/res/token/cadin_3.png differ diff --git a/res/token/cleric_female.png b/res/token/cleric_female.png new file mode 100644 index 0000000..9a0bf9e Binary files /dev/null and b/res/token/cleric_female.png differ diff --git a/res/token/cleric_male.png b/res/token/cleric_male.png new file mode 100644 index 0000000..290c894 Binary files /dev/null and b/res/token/cleric_male.png differ diff --git a/res/token/cloaked_person.png b/res/token/cloaked_person.png new file mode 100644 index 0000000..be0eeb5 Binary files /dev/null and b/res/token/cloaked_person.png differ diff --git a/res/token/dragonfolk_1.png b/res/token/dragonfolk_1.png new file mode 100644 index 0000000..15c9b39 Binary files /dev/null and b/res/token/dragonfolk_1.png differ diff --git a/res/token/dragonfolk_2.png b/res/token/dragonfolk_2.png new file mode 100644 index 0000000..c6e99b7 Binary files /dev/null and b/res/token/dragonfolk_2.png differ diff --git a/res/token/dragonfolk_3.png b/res/token/dragonfolk_3.png new file mode 100644 index 0000000..635ab81 Binary files /dev/null and b/res/token/dragonfolk_3.png differ diff --git a/res/token/dragonfolk_knight_1.png b/res/token/dragonfolk_knight_1.png new file mode 100644 index 0000000..8dad913 Binary files /dev/null and b/res/token/dragonfolk_knight_1.png differ diff --git a/res/token/dragonfolk_knight_2.png b/res/token/dragonfolk_knight_2.png new file mode 100644 index 0000000..16eca5a Binary files /dev/null and b/res/token/dragonfolk_knight_2.png differ diff --git a/res/token/dragonfolk_knight_3.png b/res/token/dragonfolk_knight_3.png new file mode 100644 index 0000000..76f8a1f Binary files /dev/null and b/res/token/dragonfolk_knight_3.png differ diff --git a/res/token/drawf_m_1.png b/res/token/drawf_m_1.png new file mode 100644 index 0000000..c1180c6 Binary files /dev/null and b/res/token/drawf_m_1.png differ diff --git a/res/token/druid_male.png b/res/token/druid_male.png new file mode 100644 index 0000000..893b45f Binary files /dev/null and b/res/token/druid_male.png differ diff --git a/res/token/dwarf_m_1.png b/res/token/dwarf_m_1.png new file mode 100644 index 0000000..c6d5874 Binary files /dev/null and b/res/token/dwarf_m_1.png differ diff --git a/res/token/dwarf_m_2.png b/res/token/dwarf_m_2.png new file mode 100644 index 0000000..12a8362 Binary files /dev/null and b/res/token/dwarf_m_2.png differ diff --git a/res/token/feline_1.png b/res/token/feline_1.png new file mode 100644 index 0000000..a23cc70 Binary files /dev/null and b/res/token/feline_1.png differ diff --git a/res/token/knight_1.png b/res/token/knight_1.png new file mode 100644 index 0000000..912bc99 Binary files /dev/null and b/res/token/knight_1.png differ diff --git a/res/token/naexi_anthro.png b/res/token/naexi_anthro.png new file mode 100644 index 0000000..b2886df Binary files /dev/null and b/res/token/naexi_anthro.png differ diff --git a/res/token/naexi_human_noweapon.png b/res/token/naexi_human_noweapon.png new file mode 100644 index 0000000..576ba42 Binary files /dev/null and b/res/token/naexi_human_noweapon.png differ diff --git a/res/token/naexi_human_yklwa.png b/res/token/naexi_human_yklwa.png new file mode 100644 index 0000000..54f0d87 Binary files /dev/null and b/res/token/naexi_human_yklwa.png differ diff --git a/res/token/robot_1.png b/res/token/robot_1.png new file mode 100644 index 0000000..01ab162 Binary files /dev/null and b/res/token/robot_1.png differ diff --git a/res/token/rockfriend_1.png b/res/token/rockfriend_1.png new file mode 100644 index 0000000..3351d00 Binary files /dev/null and b/res/token/rockfriend_1.png differ diff --git a/res/token/rockfriend_2.png b/res/token/rockfriend_2.png new file mode 100644 index 0000000..190b845 Binary files /dev/null and b/res/token/rockfriend_2.png differ diff --git a/res/token/rockfriend_3.png b/res/token/rockfriend_3.png new file mode 100644 index 0000000..9ffc928 Binary files /dev/null and b/res/token/rockfriend_3.png differ diff --git a/res/token/rockfriend_4.png b/res/token/rockfriend_4.png new file mode 100644 index 0000000..1b1aa10 Binary files /dev/null and b/res/token/rockfriend_4.png differ diff --git a/res/token/skeleton.png b/res/token/skeleton.png new file mode 100644 index 0000000..3005d22 Binary files /dev/null and b/res/token/skeleton.png differ diff --git a/res/token/tori_1.png b/res/token/tori_1.png new file mode 100644 index 0000000..4311c6c Binary files /dev/null and b/res/token/tori_1.png differ diff --git a/res/token/tori_2.png b/res/token/tori_2.png new file mode 100644 index 0000000..fc7f9a2 Binary files /dev/null and b/res/token/tori_2.png differ diff --git a/res/token/tori_3.png b/res/token/tori_3.png new file mode 100644 index 0000000..bb8e916 Binary files /dev/null and b/res/token/tori_3.png differ diff --git a/res/token/tori_4.png b/res/token/tori_4.png new file mode 100644 index 0000000..841f379 Binary files /dev/null and b/res/token/tori_4.png differ diff --git a/res/token/treasure.png b/res/token/treasure.png new file mode 100644 index 0000000..9478d18 Binary files /dev/null and b/res/token/treasure.png differ diff --git a/res/token/wizard_female.png b/res/token/wizard_female.png new file mode 100644 index 0000000..16d2b6a Binary files /dev/null and b/res/token/wizard_female.png differ diff --git a/res/token/wizard_male.png b/res/token/wizard_male.png new file mode 100644 index 0000000..ba62dd0 Binary files /dev/null and b/res/token/wizard_male.png differ diff --git a/res/ui/button_generic.png b/res/ui/button_generic.png new file mode 100644 index 0000000..c0b7630 Binary files /dev/null and b/res/ui/button_generic.png differ diff --git a/res/ui/button_grid.png b/res/ui/button_grid.png new file mode 100644 index 0000000..ee1a925 Binary files /dev/null and b/res/ui/button_grid.png differ diff --git a/res/ui/button_side_menu.png b/res/ui/button_side_menu.png new file mode 100644 index 0000000..df064ec Binary files /dev/null and b/res/ui/button_side_menu.png differ diff --git a/res/button_undo_redo.png b/res/ui/history_manipulation.png similarity index 100% rename from res/button_undo_redo.png rename to res/ui/history_manipulation.png diff --git a/res/button_edit_mode.png b/res/ui/mode_switch.png similarity index 100% rename from res/button_edit_mode.png rename to res/ui/mode_switch.png diff --git a/res/ui/quick_selector.png b/res/ui/quick_selector.png new file mode 100644 index 0000000..7244e81 Binary files /dev/null and b/res/ui/quick_selector.png differ diff --git a/res/ui/sidebar_bg.png b/res/ui/sidebar_bg.png new file mode 100644 index 0000000..682759f Binary files /dev/null and b/res/ui/sidebar_bg.png differ diff --git a/res/ui/sidebar_cursor.png b/res/ui/sidebar_cursor.png new file mode 100644 index 0000000..8b93228 Binary files /dev/null and b/res/ui/sidebar_cursor.png differ diff --git a/res/ui/sidebar_folder.png b/res/ui/sidebar_folder.png new file mode 100644 index 0000000..d0b0aa5 Binary files /dev/null and b/res/ui/sidebar_folder.png differ diff --git a/res/ui/sidebar_overlay.png b/res/ui/sidebar_overlay.png new file mode 100644 index 0000000..8cd4484 Binary files /dev/null and b/res/ui/sidebar_overlay.png differ diff --git a/res/ui/text_box.png b/res/ui/text_box.png new file mode 100644 index 0000000..35ebbab Binary files /dev/null and b/res/ui/text_box.png differ diff --git a/res/ui/text_input.png b/res/ui/text_input.png new file mode 100644 index 0000000..252b8f0 Binary files /dev/null and b/res/ui/text_input.png differ diff --git a/src/Chat.ts b/src/Chat.ts new file mode 100644 index 0000000..4e3155d --- /dev/null +++ b/src/Chat.ts @@ -0,0 +1,58 @@ +class Chat extends Phaser.GameObjects.Container { + textInput: TextInput; + messageContainer: Phaser.GameObjects.Container; + messages: ChatBox[] = []; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + + this.textInput = new TextInput(scene, 0, 0); + this.list.push(this.textInput); + + this.messageContainer = new Phaser.GameObjects.Container(scene, 0, 0); + this.list.push(this.messageContainer); + } + + update() { + this.textInput.y = -this.textInput.getHeight(); + this.messageContainer.y = this.textInput.y - 3; + } + + pushMessage(message: string): void { + this.messages.unshift(new ChatBox(this.scene, 0, 0, message)); + this.messageContainer.list.push(this.messages[0]); + this.scene.tweens.add({ + targets: this.messages[0], + alpha: {from: 0, to: 1}, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + this.reflowMessages(); + } + + reflowMessages(): void { + let y = 0; + for (let message of this.messages) { + y -= message.getHeight() + 9; + + if (y + message.getHeight() < -400) { + this.scene.tweens.add({ + targets: message, + alpha: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + + this.scene.tweens.add({ + targets: message, + y: y, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + } +} diff --git a/src/Chatbox.ts b/src/Chatbox.ts new file mode 100644 index 0000000..d9767a6 --- /dev/null +++ b/src/Chatbox.ts @@ -0,0 +1,76 @@ +class ChatBox extends Phaser.GameObjects.Container { + str: string; + texture: string = "ui_text_box"; + + private FONT_SIZE = 4.3; + private chatboxHeight: number = 0; + + constructor(scene: Phaser.Scene, x: number, y: number, str: string, tex?: string) { + super(scene, x, y); + this.str = str; + if (tex != undefined) this.texture = tex; + + this.setText(str); + } + + setText(text: string): void { + this.list.forEach((e) => e.destroy()); + this.list = []; + this.str = text; + + let testObj = new Phaser.GameObjects.BitmapText(this.scene, 15, 4, "font2x", "AB", this.FONT_SIZE, 0); + + const letterWidth = testObj.getTextBounds().global.width / 2; + const maxLetters = 95 / letterWidth; + + const split = this.str.split(/( )/g); + let lines = []; + + function nextLine() { + let newLine = ""; + while (`${newLine} ${split[0]}`.length < maxLetters && split.length) newLine += split.shift(); + lines.push(newLine.trim()); + if (split.length) nextLine(); + } + + nextLine(); + + let top = new Phaser.GameObjects.Sprite(this.scene, 0, 0, this.texture, 0); + top.setScale(3, 3); + top.setOrigin(0, 0); + top.setAlpha(0.6); + this.list.push(top); + + let i = 0; + for (let line of lines) { + let elem = new Phaser.GameObjects.BitmapText(this.scene, 12, 7 + i * 18, "font2x", line, this.FONT_SIZE, 0); + elem.setScale(3, 3); + elem.setOrigin(0, 0); + this.list.push(elem); + i++; + } + + let lastElem = (this.list[this.list.length - 1] as Phaser.GameObjects.BitmapText); + let height = Math.max(lastElem.y + lastElem.getTextBounds().global.height - 36, 2); + + let middle = new Phaser.GameObjects.Sprite(this.scene, 0, 18, "ui_text_box", 1); + middle.setScale(3, height / 6); + middle.setOrigin(0, 0); + middle.setAlpha(0.6); + this.list.push(middle); + this.sendToBack(middle); + + let bottom = new Phaser.GameObjects.Sprite(this.scene, 0, height + 18, this.texture, 2); + bottom.setScale(3, 3); + bottom.setOrigin(0, 0); + bottom.setAlpha(0.6); + this.list.push(bottom); + this.sendToBack(bottom); + + this.chatboxHeight = height + 18 * 2; + } + + getHeight() { + return this.chatboxHeight; + } +} diff --git a/src/HistoryElement.ts b/src/HistoryElement.ts index 74e01d3..55c6eab 100644 --- a/src/HistoryElement.ts +++ b/src/HistoryElement.ts @@ -10,26 +10,64 @@ class HistoryElement { } undo() { + console.log("Undo", this.type); if (this.type == "tile") { - for (let tile of this.data as {pos: Vec2, solid: boolean}[]) { - this.scene.map.setSolid(tile.pos.x, tile.pos.y, !tile.solid); - } + for (let tile of this.data as {pos: Vec2, solid: boolean, oldSolid: boolean, palette: number, oldPalette: number}[]) + this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.oldPalette, tile.oldSolid); } - else if (this.type == "token_move") { - let data = this.data as { start: Vec2, end: Vec2, token: Token } - data.token.setPosition(data.start.x, data.start.y); + else if (this.type == "token_modify") { + let data = this.data as { old: string, new: string }; + let uuid = JSON.parse(this.data.old).uuid; + + for (let token of this.scene.tokens) { + if (token.uuid == uuid) { + token.loadSerializedData(this.data.old); + return; + } + } + let token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.old); + this.scene.add.existing(token); + this.scene.tokens.push(token); + } + else if (this.type == "token_create") { + let uuid = JSON.parse(this.data.data).uuid; + for (let i = 0; i < this.scene.tokens.length; i++) { + if (this.scene.tokens[i].uuid == uuid) { + this.scene.tokens[i].destroy(); + this.scene.tokens.splice(i, 1); + } + } } } redo() { + console.log("Redo", this.type); if (this.type == "tile") { - for (let tile of this.data as {pos: Vec2, solid: boolean}[]) { - this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.solid); - } + for (let tile of this.data as {pos: Vec2, solid: boolean, wasSolid: boolean, palette: number, oldPalette: number}[]) + this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.palette, tile.solid); } - else if (this.type == "token_move") { - let data = this.data as { start: Vec2, end: Vec2, token: Token } - data.token.setPosition(data.end.x, data.end.y); + else if (this.type == "token_modify") { + let data = this.data as { old: string, new: string }; + let uuid = JSON.parse(this.data.old).uuid; + + for (let token of this.scene.tokens) { + if (token.uuid == uuid) { + token.loadSerializedData(this.data.new); + return; + } + } + let token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.new); + this.scene.add.existing(token); + this.scene.tokens.push(token); + } + else if (this.type == "token_create") { + let data = JSON.parse(this.data.data); + let token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.data); + this.scene.add.existing(token); + this.scene.tokens.push(token); } } } diff --git a/src/IntroScene.ts b/src/IntroScene.ts deleted file mode 100644 index a15500c..0000000 --- a/src/IntroScene.ts +++ /dev/null @@ -1,175 +0,0 @@ -// class IntroScene extends Phaser.Scene { -// stars: Star[] = []; -// pickups: Pickup[] = []; -// spark: Spark; -// text: Phaser.GameObjects.Text; - -// speed: number; -// angleChange: number; -// controllingSpark: boolean; -// animationRange: number; -// starAngle: number; -// collided: boolean; - -// canDie: boolean; - -// constructor() { -// super({key: "IntroScene"}); -// } - -// preload(): void { -// this.load.spritesheet("star", "res/star.png", {frameWidth: 8, frameHeight: 8, startFrame: 0, endFrame: 16}); -// this.load.spritesheet("spark", "res/spark.png", {frameWidth: 16, frameHeight: 16, startFrame: 0, endFrame: 64}); -// this.load.spritesheet("pickup", "res/pickup.png", {frameWidth: 16, frameHeight: 16}); -// } - -// create(): void { -// this.stars = []; -// this.pickups = []; -// this.speed = 0.25; -// this.angleChange = 0.001; -// this.controllingSpark = false; -// this.animationRange = -1; -// this.starAngle = -(Math.PI / 1.5); -// this.collided = false; -// this.canDie = false; - -// //@ts-ignore -// $("#game").removeClass('active'); - -// for (let i = 0; i < 200; i++) { -// let x = Math.round(Math.random() * (this.cameras.main.width / 4)); -// let y = Math.round(Math.random() * (this.cameras.main.height / 4)); -// this.stars.push(new Star(this, x, y)); -// } - -// for (let i = 0; i < 8; i++) { -// let x = Math.round(Math.random() * (this.cameras.main.width / 4)); -// let y = Math.round(Math.random() * (this.cameras.main.height / 4)); -// this.pickups.push(new Pickup(this, x, y)); -// } - -// this.spark = new Spark(this, this.cameras.main.width / 2, this.cameras.main.height / 2); - -// // this.text = this.add.text(4, 4, this.collisions.toString()); -// } - -// update(time: number, delta: number): void { -// if (this.input.mousePointer.primaryDown && !this.controllingSpark) { -// if (this.input.mousePointer.x > this.cameras.main.width / 2 - 16 -// && this.input.mousePointer.x < this.cameras.main.width / 2 + 16 -// && this.input.mousePointer.y > this.cameras.main.height / 2 - 16 -// && this.input.mousePointer.y < this.cameras.main.height / 2 + 16) { - -// this.controllingSpark = true; -// this.canDie = true; -// //@ts-ignore -// $("#game").addClass('active'); -// this.animationRange = 0; -// } -// } -// if (this.controllingSpark) { -// this.spark.setPosition(Math.round(this.input.mousePointer.x / 4) * 4, Math.round(this.input.mousePointer.y / 4) * 4); -// } -// if (this.animationRange != -1) { -// if (!this.collided) { -// this.fadeIn(this.animationRange*this.cameras.main.width); -// this.animationRange += 0.02; -// if (this.animationRange >= 1) this.animationRange = -1; -// } -// else { -// this.fadeOut(this.animationRange*this.cameras.main.width); -// this.animationRange -= 0.05; -// if (this.animationRange <= 0) this.scene.restart(); -// } -// } - -// if (this.speed < 5) { -// if (this.controllingSpark) { -// this.starAngle += this.angleChange; -// this.speed *= 1.001; -// this.angleChange *= 1.000005; -// } -// } -// else { -// this.controllingSpark = false; -// this.canDie = false; -// this.starAngle = Math.PI * 1.5; -// this.speed *= 1.02; - -// if (this.speed < 10) this.spark.moveToCenter(); -// if (this.speed > 10) this.spark.y += this.speed; -// if (this.speed > 15) this.spark.explode(); - -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(15, 11, 31), new Phaser.Display.Color(255, 255, 255), 30, Math.min(Math.max(this.speed - 10, 0), 30)); -// this.cameras.main.setBackgroundColor(hexColor); - -// if (this.speed >= 60) { -// this.game.scene.start('MainScene'); -// this.game.scene.stop('IntroScene'); -// this.game.scene.swapPosition('MainScene', 'IntroScene'); -// return; -// } -// } - -// let yOff = Math.sin(this.starAngle); -// let xOff = Math.cos(this.starAngle); - -// for (let star of this.stars) { -// star.push(xOff * this.speed, yOff * this.speed); -// star.stayOnScreen(); -// } -// for (let pickup of this.pickups) { -// pickup.push(xOff * this.speed, yOff * this.speed); -// if (this.canDie) { -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.spark.x), 2) -// + Math.pow(Math.abs(pickup.y - this.spark.y), 2)); -// if (distance < 32 && !this.collided) { -// this.collided = true; -// this.animationRange = 0.7; -// this.controllingSpark = false; -// this.spark.explode(); -// } -// } -// } -// } - -// fadeIn(range: number) { -// for (let star of this.stars) { -// let distance = Math.sqrt(Math.pow(Math.abs(star.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(star.y - this.cameras.main.height/2), 2)); -// if (range > distance && range < distance + 200) star.fadeIn(); -// if (range > distance + 200) star.fadeReg(); -// } - -// for (let pickup of this.pickups) { -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(pickup.y - this.cameras.main.height/2), 2)); -// if (range + 200 > distance) pickup.makeExists(); -// } - -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(0, 0, 0), new Phaser.Display.Color(15, 11, 31), 1, this.animationRange); -// this.cameras.main.setBackgroundColor(hexColor); -// } - -// fadeOut(range: number) { -// for (let star of this.stars) { -// let distance = Math.sqrt(Math.pow(Math.abs(star.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(star.y - this.cameras.main.height/2), 2)); -// if (range > distance && range < distance + 200) star.fadeIn(); -// if (range < distance) star.fadeOut(); -// } - -// for (let i = 0; i < this.pickups.length; i++) { -// let pickup = this.pickups[i]; -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(pickup.y - this.cameras.main.height/2), 2)); -// if (range - 200 < distance) { -// pickup.setAlpha(0); -// } -// } - -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(0, 0, 0), new Phaser.Display.Color(15, 11, 31), 0.8, this.animationRange); -// this.cameras.main.setBackgroundColor(hexColor); -// } -// } diff --git a/src/LoadScene.ts b/src/LoadScene.ts deleted file mode 100644 index 725e493..0000000 --- a/src/LoadScene.ts +++ /dev/null @@ -1,22 +0,0 @@ -class LoadScene extends Phaser.Scene { - constructor() { - super({key: "LoadScene"}); - } - - preload(): void { - this.cameras.main.setBackgroundColor("#300"); - - //TODO: Find out why loaded assets aren't propogating - } - - create(): void { - this.game.scene.start('MainScene'); - this.game.scene.stop('LoadScene'); - this.game.scene.swapPosition('MainScene', 'LoadScene'); - } - - update(time: number, delta: number): void { - - } -} - diff --git a/src/Main.ts b/src/Main.ts index 112f993..f89e25f 100644 --- a/src/Main.ts +++ b/src/Main.ts @@ -10,7 +10,7 @@ window.onload = () => { parent: "game", backgroundColor: "#000000", antialias: false, - scene: [MainScene, LoadScene], + scene: [GetAssetsScene, LoadScene, MainScene], physics: { default: "arcade", arcade: { diff --git a/src/OutlinePipeline.ts b/src/OutlinePipeline.ts index fe0a07c..58ff4a2 100644 --- a/src/OutlinePipeline.ts +++ b/src/OutlinePipeline.ts @@ -4,20 +4,30 @@ class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.TextureTintPipelin renderer: game.renderer, fragShader: ` precision mediump float; + uniform sampler2D uMainSampler; + uniform float tex_size; + varying vec2 outTexCoord; + void main(void) { - vec4 color = texture2D(uMainSampler, outTexCoord); - vec4 colorU = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y - 0.055)); - vec4 colorD = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y + 0.055)); - vec4 colorL = texture2D(uMainSampler, vec2(outTexCoord.x + 0.055, outTexCoord.y)); - vec4 colorR = texture2D(uMainSampler, vec2(outTexCoord.x - 0.055, outTexCoord.y)); - - gl_FragColor = color; + float factor = 1.0 / tex_size; + + vec4 color = texture2D(uMainSampler, outTexCoord); + vec4 colorU = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y + factor)); + vec4 colorD = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y - factor)); + vec4 colorL = texture2D(uMainSampler, vec2(outTexCoord.x + factor, outTexCoord.y)); + vec4 colorR = texture2D(uMainSampler, vec2(outTexCoord.x - factor, outTexCoord.y)); if (color.a == 0.0 && (colorU.a != 0.0 || colorD.a != 0.0 || colorL.a != 0.0 || colorR.a != 0.0) ) { gl_FragColor = vec4(1.0, 1.0, 1.0, .2); } + else { + if (color.a == 0.0) discard; + color += vec4(0.1, 0.1, 0.1, 0); + gl_FragColor = color; + } + }` }; super(config); diff --git a/src/TextInput.ts b/src/TextInput.ts new file mode 100644 index 0000000..8938f9b --- /dev/null +++ b/src/TextInput.ts @@ -0,0 +1,25 @@ +class TextInput extends ChatBox { + text: string = ""; + + constructor(scene: Phaser.Scene, x: number, y: number) { + super(scene, x, y, " ", "ui_text_input"); + + document.addEventListener("keydown", (e) => { + let code = e.keyCode; + + if (code == 8) { + this.text = this.text.substr(0, this.text.length - 1); + this.setText(this.text); + return; + } + else if (code == 13) { + //Send + return; + } + else if (e.key.length != 1) return; + + this.text += e.key; + this.setText(this.text.length == 0 ? " " : this.text); + }) + } +} diff --git a/src/TileMap.ts b/src/TileMap.ts index f7c2b4a..32fe638 100644 --- a/src/TileMap.ts +++ b/src/TileMap.ts @@ -1,5 +1,5 @@ class TileMap { - scene: Phaser.Scene; + scene: MainScene; key: string; dimensions: {x: number, y: number} @@ -7,94 +7,116 @@ class TileMap { SOLID: number = 10; map: Phaser.Tilemaps.Tilemap; - layer: Phaser.Tilemaps.DynamicTilemapLayer; + layers: (Phaser.Tilemaps.DynamicTilemapLayer | null)[] = []; - constructor(key: string, scene: Phaser.Scene, xwid: number, ywid: number) { + solid_at: boolean[][]; + palette_at: number[][]; + + constructor(key: string, scene: MainScene, xwid: number, ywid: number) { this.key = key; this.scene = scene; this.dimensions = {x: xwid, y: ywid}; + this.solid_at = []; + this.palette_at = []; + for (let i = 0; i < xwid; i++) { + this.solid_at[i] = []; + this.palette_at[i] = []; + for (let j = 0; j < ywid; j++) { + this.solid_at[i][j] = false; + this.palette_at[i][j] = 1; + } + } + this.map = this.scene.add.tilemap(null, 16, 16, 0, 0); - let tileset = this.map.addTilesetImage("tileset", "tileset", 16, 16, 0, 0); - this.layer = this.map.createBlankDynamicLayer("layer_0", "tileset", 0, 0, 50*16, 50*16, 16, 16); - this.layer.setScale(4, 4); - this.layer.setInteractive(); + for (let i = 0; i < this.scene.TILESET_COUNT; i++) { + let tileset = this.map.addTilesetImage("tileset_" + i, "tileset_" + i, 16, 16, 0, 0); + + this.layers[i] = null; + } + this.createLayer(0); + this.layers[0].setInteractive(); - // this.map.addTilesetImage("grid_tile", "grid_tile", 16, 16, 0, 0); - // this.map.setLayer("grid"); - // let gridlayer = this.map.createBlankDynamicLayer("grid", "grid_tile", 0, 0, 50*16, 50*16, 16, 16); - // gridlayer.setScale(4, 4); - // for (let i = 0; i < xwid; i++) { - // for (let j = 0; j < ywid; j++) { - // if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) gridlayer.putTileAt(0, i, j); - // } - // } - } - - fillMap(tid?: number): void { - if (!tid) tid = this.SOLID; + this.map.addTilesetImage("grid_tile", "grid_tile", 16, 16, 0, 0); + this.map.setLayer("grid"); + let gridlayer = this.map.createBlankDynamicLayer("grid", "grid_tile", 0, 0, 50*16, 50*16, 16, 16); + gridlayer.setScale(4, 4); + gridlayer.setDepth(500); + for (let i = 0; i < xwid; i++) { + for (let j = 0; j < ywid; j++) { + if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) gridlayer.putTileAt(0, i, j); + } + } for (let x = 0; x < this.dimensions.x; x ++) { for (let y = 0; y < this.dimensions.y; y ++) { - this.setTile(x, y, tid); + this.setTile(x, y, 1, 13); } } } - setSolid(x: number, y: number, solid: boolean): boolean { - let alreadySolid = this.getSolid(x, y); - if (alreadySolid == solid) return false; + private createLayer(palette: number) { + this.map.setLayer("layer_" + palette); + this.layers[palette] = this.map.createBlankDynamicLayer("layer_" + palette, "tileset_" + palette, 0, 0, 50*16, 50*16, 16, 16); + this.layers[palette].setScale(4, 4); + this.layers[palette].setDepth(-500 + palette); + } - if (solid) this.setTile(x, y, this.SOLID); - else this.setTile(x, y, 13); + setSolid(x: number, y: number, palette: number, solid: boolean): boolean { + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return false; + let oldPalette = this.palette_at[x][y]; + let wasSolid = this.solid_at[x][y]; + + if (wasSolid == solid && palette == oldPalette) return false; + + this.setTile(x, y, palette, (solid ? this.SOLID : 13)); this.calculateEdgesAround(x, y); + return true; } - getSolid(x: number, y: number) { - return this.getTile(x, y) == this.SOLID; + getSolid(x: number, y: number): number { + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return -1; + return (this.solid_at[x][y]) ? this.palette_at[x][y] : -1; } - private setTile(x: number, y: number, tid: number): void { - this.layer.removeTileAt(x, y, true); - this.layer.putTileAt(tid, x, y); + getPalette(x: number, y: number): number { + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return -1; + return this.palette_at[x][y]; } - private getTile(x: number, y: number): number { - if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return this.SOLID; - return this.layer.getTileAt(x, y, true).index; + private setTile(x: number, y: number, palette: number, tid: number): void { + if (this.layers[palette] == null) this.createLayer(palette); + + this.layers[this.palette_at[x][y]].removeTileAt(x, y, true); + this.layers[palette].putTileAt(tid, x, y); + this.palette_at[x][y] = palette; + this.solid_at[x][y] = tid == this.SOLID; } private calculateEdgesAround(x: number, y: number) { - for (let i = clamp(x - 1, this.dimensions.x - 1, 0); i <= clamp(x + 1, this.dimensions.x + 1, 0); i++) { - for (let j = clamp(y - 1, this.dimensions.y - 1, 0); j <= clamp(y + 1, this.dimensions.y + 1, 0); j++) { - this.calculateEdges(i, j); + for (let i = clamp(x - 1, this.dimensions.x - 1, 0); i <= clamp(x + 1, this.dimensions.x - 1, 0); i++) { + for (let j = clamp(y - 1, this.dimensions.y - 1, 0); j <= clamp(y + 1, this.dimensions.y - 1, 0); j++) { + let tile = this.calculateEdges(i, j); + if (tile != -1) this.setTile(i, j, this.palette_at[i][j], tile); } } } - private getSurroundingTiles(x: number, y: number): number[] { - let tiles: number[] = []; - for (let i = -1; i <= 1; i++) { - for (let j = -1; j <= 1; j++) { - tiles.push(this.getTile(x + j, y + i)); - } - } - return tiles; - } - private getSurroundingSolid(x: number, y: number): boolean[] { - let tiles: (number|boolean)[] = this.getSurroundingTiles(x, y); - for (let i = 0; i < 9; i++) { - tiles[i] = (tiles[i] == this.SOLID); + let solid: boolean[] = []; + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + solid.push(this.getSolid(x + j, y + i) != -1); + } } - return tiles as boolean[]; + return solid; } - private calculateEdges(x: number, y: number): void { - if (this.getTile(x, y) == this.SOLID) return; + private calculateEdges(x: number, y: number): number { + if (this.getSolid(x, y) != -1) return -1; let adjacents = this.getSurroundingSolid(x, y); let tile = 13; @@ -188,7 +210,7 @@ class TileMap { } else if (adjacents[8] /*Bottom right*/) tile = 0; - this.setTile(x, y, tile); + return tile; } } diff --git a/src/TilesetPatcher.ts b/src/TilesetPatcher.ts new file mode 100644 index 0000000..669c8b3 --- /dev/null +++ b/src/TilesetPatcher.ts @@ -0,0 +1,14 @@ +class TilesetPatcher { + constructor(scene: Phaser.Scene) { + let renderTex = new Phaser.GameObjects.RenderTexture(scene, 0, 0, 9 * 16, 7 * 16 * 8); + renderTex.drawFrame("tileset_0", 0, 0, 7 * 16 * 0); + renderTex.drawFrame("tileset_1", 0, 0, 7 * 16 * 1); + renderTex.drawFrame("tileset_2", 0, 0, 7 * 16 * 2); + + scene.add.existing(renderTex); + // scene.textures.addRenderTexture("tileset_16x", renderTex); + + // let spr = scene.add.sprite(300, 300, "tileset_16x"); + // console.log(spr); + } +} diff --git a/src/Token.ts b/src/Token.ts index 36aedf7..7a53afb 100644 --- a/src/Token.ts +++ b/src/Token.ts @@ -1,35 +1,73 @@ +interface SerializedToken { + uuid: string, + sprite: string, + frame: number, + x: number, + y: number +} + class Token extends Phaser.GameObjects.Container { - sprite: Phaser.GameObjects.Sprite; - shadow: Phaser.GameObjects.Sprite; + sprite: Phaser.GameObjects.Sprite | null = null; + shadow: Phaser.GameObjects.Sprite | null = null; + + currentFrame: number = 0; + + uuid: string; width: number; height: number; constructor(scene: Phaser.Scene, x: number, y: number, tex: string) { super(scene, x, y); + this.setTexture(tex); - this.shadow = new Phaser.GameObjects.Sprite(scene, -4, -4, tex); - this.shadow.setOrigin(0, 0); - this.shadow.setScale(4, 1); - this.shadow.setTint(0x000000); - this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3); - this.list.push(this.shadow); + this.uuid = generateId(32); + } + + private setTexture(tex: string) { + if (this.shadow != null) this.shadow.setTexture(tex); + else { + this.shadow = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex); + this.shadow.setOrigin(0, 0); + this.shadow.setScale(4, 1); + this.shadow.setTint(0x000000); + this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3); + this.list.push(this.shadow); + } this.width = this.shadow.width * 4; this.height = this.shadow.height * 4; this.shadow.y = this.height - 24; - this.sprite = new Phaser.GameObjects.Sprite(scene, -4, -4, tex); - this.sprite.setOrigin(0, 0); - this.sprite.setScale(4, 4); - this.setPosition(x, y); - this.list.push(this.sprite); + if (this.sprite != null) this.sprite.setTexture(tex); + else { + this.sprite = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex); + this.sprite.setOrigin(0, 0); + this.sprite.setScale(4, 4); + this.setPosition(this.x / 4, this.y / 4); + this.list.push(this.sprite); + } + } - this.scene.add.existing(this); + setFrame(frame: number) { + this.currentFrame = frame; + this.sprite.setFrame(frame); + this.shadow.setFrame(frame); + } + + getFrame(): number { + return this.currentFrame; + } + + frameCount(): number { + return Object.keys(this.sprite.texture.frames).length - 1; } toggleOutline(outline: boolean) { - if (outline) this.sprite.setPipeline("outline"); + if (outline) { + this.sprite.setPipeline("outline"); + this.sprite.pipeline.setFloat1("tex_size", this.sprite.texture.source[0].width); + } else this.sprite.resetPipeline(); } @@ -41,4 +79,30 @@ class Token extends Phaser.GameObjects.Container { getPosition(): Vec2 { return new Vec2(this.x / 4, this.y / 4); } + + // For converting token to / from serialized data + + serialize(): string { + return JSON.stringify(({ + uuid: this.uuid, + sprite: this.sprite.texture.key, + frame: this.currentFrame, + x: this.x / 4, + y: this.y / 4 + } as SerializedToken)); + } + + static deserialize(scene: Phaser.Scene, serialized: string): Token { + let tkn = new Token(scene, 0, 0, ""); + tkn.loadSerializedData(serialized); + return tkn; + } + + loadSerializedData(serialized: string) { + let tbl: SerializedToken = JSON.parse(serialized); + this.uuid = tbl.uuid; + this.setTexture(tbl.sprite); + this.setFrame(tbl.frame) + this.setPosition(tbl.x, tbl.y); + } } diff --git a/src/UIView.ts b/src/UIView.ts index 330365b..d601ae0 100644 --- a/src/UIView.ts +++ b/src/UIView.ts @@ -1,12 +1,16 @@ class UIView { - scene: Phaser.Scene; + scene: MainScene; camera: Phaser.Cameras.Scene2D.Camera; o: Phaser.GameObjects.Container; + visibleMenu: number = 0; uiActive: boolean = false; - constructor(scene) { + tileSidebar: UITileSidebar; + tokenSidebar: UITokenSidebar; + + constructor(scene: MainScene) { this.scene = scene; this.camera = this.scene.cameras.add(0, 0, this.scene.cameras.main.width, this.scene.cameras.main.height, false, "ui_camera"); this.camera.scrollX = -10000; @@ -14,11 +18,83 @@ class UIView { this.o = this.scene.add.container(-10000, 0); } + createElements() { + this.o.add(new UIModeSwitchButton(this.scene, 14 + 10, 1)); + this.o.add(new UIHistoryManipulation(this.scene, 14 + 25, 1)); + + this.tokenSidebar = new UITokenSidebar(this.scene, -205, 0); + this.o.add(this.tokenSidebar); + for (let t of TOKENS) { + this.tokenSidebar.addToken(t.key); + } + + this.tileSidebar = new UITileSidebar(this.scene, 0, 0); + this.o.add(this.tileSidebar); + this.tileSidebar.addPalette(0); + this.tileSidebar.addPalette(1); + this.tileSidebar.addPalette(2); + + } + update() { this.uiActive = false; for (let o of this.o.list) { o.update(); if (!this.uiActive && (o as UIComponent).mouseIntersects()) this.uiActive = true; } + + if (this.visibleMenu != this.scene.mode) { + this.visibleMenu = this.scene.mode; + if (this.scene.mode == 0) { + this.displayArchitect(); + this.hideToken(); + } + else { + this.hideArchitect(); + this.displayToken(); + } + } + } + + displayArchitect() { + this.o.bringToTop(this.tileSidebar); + this.scene.tweens.add({ + targets: this.tileSidebar, + x: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + + hideToken() { + this.scene.tweens.add({ + targets: this.tokenSidebar, + x: -205, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + + displayToken() { + this.o.bringToTop(this.tokenSidebar); + this.scene.tweens.add({ + targets: this.tokenSidebar, + x: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + + hideArchitect() { + this.scene.tweens.add({ + targets: this.tileSidebar, + x: -205, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); } } diff --git a/src/Util.ts b/src/Util.ts index d3677fe..3f65a4a 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -6,3 +6,15 @@ function clamp(x: number, min: number, max: number) { } return Math.max(Math.min(x, max), min); } + +function dec2hex (dec) { + return ('0' + dec.toString(16)).substr(-2) +} + +function generateId(len): string { + let arr = new Uint8Array((len || 40) / 2) + window.crypto.getRandomValues(arr); + let stringArr: string[] = []; + for (let i = 0; i < arr.length; i++) stringArr.push(dec2hex(arr[i])); + return stringArr.join(''); +} diff --git a/src/WorldView.ts b/src/WorldView.ts index 05ca8f9..33d2247 100644 --- a/src/WorldView.ts +++ b/src/WorldView.ts @@ -1,5 +1,5 @@ class WorldView { - scene: Phaser.Scene; + scene: MainScene; camera: Phaser.Cameras.Scene2D.Camera; cursorScreen: Vec2 = new Vec2(); @@ -10,7 +10,7 @@ class WorldView { zoomLevels: number[] = [10, 17, 25, 33, 40, 50, 60, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500]; zoomLevel = 11; - constructor(scene) { + constructor(scene: MainScene) { this.scene = scene; this.camera = this.scene.cameras.main; @@ -27,9 +27,11 @@ class WorldView { } private onWheel(e: WheelEvent) { - let dir = (e.deltaY < 0 ? 1 : -1); - this.zoomLevel = clamp(this.zoomLevel + dir, 0, this.zoomLevels.length - 1); - this.camera.setZoom(this.zoomLevels[this.zoomLevel] / 100); + if (!(this.scene.mode == 1 && this.scene.token.currentToken != null)) { + let dir = (e.deltaY < 0 ? 1 : -1); + this.zoomLevel = clamp(this.zoomLevel + dir, 0, this.zoomLevels.length - 1); + this.camera.setZoom(this.zoomLevels[this.zoomLevel] / 100); + } } private pan() { diff --git a/src/data/TOKENS.ts b/src/data/TOKENS.ts new file mode 100644 index 0000000..33c68de --- /dev/null +++ b/src/data/TOKENS.ts @@ -0,0 +1,46 @@ +interface TokenFileProps { + name: string, + key: string, + file: string, + split_by?: number +} + +const TOKENS: TokenFileProps[] = [ + { name: "Armor 1", key: "tkn_armor_1", file: "res/token/armor_1", split_by: 18 }, + { name: "Cadin 1", key: "tkn_cadin_1", file: "res/token/cadin_1", split_by: 18 }, + { name: "Cadin 2", key: "tkn_cadin_2", file: "res/token/cadin_2", split_by: 18 }, + { name: "Cadin 3", key: "tkn_cadin_3", file: "res/token/cadin_3", split_by: 18 }, + { name: "Cleric F", key: "tkn_cleric_f", file: "res/token/cleric_female", split_by: 18 }, + { name: "Cleric M", key: "tkn_cleric_m", file: "res/token/cleric_male", split_by: 18 }, + { name: "Dragonfolk 1", key: "tkn_dragonfolk_1", file: "res/token/dragonfolk_1", split_by: 18 }, + { name: "Dragonfolk 2", key: "tkn_dragonfolk_2", file: "res/token/dragonfolk_2", split_by: 18 }, + { name: "Dragonfolk 3", key: "tkn_dragonfolk_3", file: "res/token/dragonfolk_3", split_by: 18 }, + { name: "Tori 1", key: "tkn_tori_1", file: "res/token/tori_1", split_by: 18 }, + { name: "Tori 2", key: "tkn_tori_2", file: "res/token/tori_2", split_by: 18 }, + { name: "Tori 3", key: "tkn_tori_3", file: "res/token/tori_3", split_by: 18 }, + { name: "Tori 4", key: "tkn_tori_4", file: "res/token/tori_4", split_by: 18 }, + { name: "Dragonfolk Knight 1", key: "tkn_dragonknight_1", file: "res/token/dragonfolk_knight_1", split_by: 18 }, + { name: "Dragonfolk Knight 2", key: "tkn_dragonknight_2", file: "res/token/dragonfolk_knight_2", split_by: 18 }, + { name: "Dragonfolk Knight 3", key: "tkn_dragonknight_3", file: "res/token/dragonfolk_knight_3", split_by: 18 }, + { name: "Druid M", key: "tkn_druid_m", file: "res/token/druid_male", split_by: 18 }, + { name: "Feline 1", key: "tkn_feline_1", file: "res/token/feline_1", split_by: 18 }, + { name: "Knight 1", key: "tkn_knight_1", file: "res/token/knight_1", split_by: 18 }, + { name: "Robot 1", key: "tkn_robot_1", file: "res/token/robot_1", split_by: 18 }, + { name: "Rockfriend Green", key: "tkn_rockfriend_g", file: "res/token/rockfriend_1", split_by: 18 }, + { name: "Rockfriend Blue", key: "tkn_rockfriend_b", file: "res/token/rockfriend_2", split_by: 18 }, + { name: "Rockfriend Red", key: "tkn_rockfriend_r", file: "res/token/rockfriend_3", split_by: 18 }, + { name: "Rockfriend Teal", key: "tkn_rockfriend_t", file: "res/token/rockfriend_4", split_by: 18 }, + { name: "Wizard F", key: "tkn_wizard_f", file: "res/token/wizard_female", split_by: 18 }, + { name: "Wizard M", key: "tkn_wizard_m", file: "res/token/wizard_male", split_by: 18 }, + { name: "Cloaked Person", key: "tkn_cloaked_person", file: "res/token/cloaked_person", split_by: 18 }, + { name: "Dwarf M 1", key: "tkn_dwarf_m_1", file: "res/token/dwarf_m_1", split_by: 18 }, + { name: "Dwarf M 2", key: "tkn_dwarf_m_2", file: "res/token/dwarf_m_2", split_by: 18 }, + { name: "Skeleton", key: "tkn_skeleton", file: "res/token/skeleton", split_by: 18 }, + + { name: "Naexi", key: "tkn_naexi", file: "res/token/naexi_human_noweapon", split_by: 18 }, + { name: "Naexi w/ Yklwa", key: "tkn_naexi_yklwa", file: "res/token/naexi_human_yklwa", split_by: 18 }, + { name: "Naexi Anthro Form", key: "tkn_naexi_anthro", file: "res/token/naexi_anthro", split_by: 18 }, + + { name: "bones", key: "tkn_bones", file: "res/token/bones" }, + { name: "treasure", key: "tkn_treasure", file: "res/token/treasure" }, +]; diff --git a/src/manip/ArchitectMode.ts b/src/manip/ArchitectMode.ts index 9c0f6ab..a3641c9 100644 --- a/src/manip/ArchitectMode.ts +++ b/src/manip/ArchitectMode.ts @@ -3,9 +3,14 @@ class ArchitectMode { active: boolean = false; cursor: Phaser.GameObjects.Sprite; + primitives: Phaser.GameObjects.Line[] = []; + startTilePos: Vec2 = new Vec2(); + placeMode: string = "brush"; pointerDown: boolean = false; - manipulated: {pos: Vec2, solid: boolean}[] = []; + pointerPrimaryDown: boolean = false; + + manipulated: {pos: Vec2, solid: boolean, oldSolid: boolean, palette: number, oldPalette: number}[] = []; constructor(scene: MainScene) { this.scene = scene; @@ -15,6 +20,11 @@ class ArchitectMode { this.cursor.setScale(4, 4); this.cursor.setDepth(1000); this.cursor.setOrigin(0, 0); + + this.scene.snapKey.addListener("down", () => { if (!this.scene.input.activePointer.isDown) this.placeMode = "line" }); + this.scene.modifierKey.addListener("down", () => { if (!this.scene.input.activePointer.isDown) this.placeMode = "rect" }); + this.scene.snapKey.addListener("up", () => { if (!this.scene.input.activePointer.isDown) this.placeMode = "brush" }); + this.scene.modifierKey.addListener("up", () => { if (!this.scene.input.activePointer.isDown) this.placeMode = "brush" }); } update() { @@ -27,15 +37,131 @@ class ArchitectMode { this.cursor.setVisible((selectedTilePos.x >= 0 && selectedTilePos.y >= 0 && selectedTilePos.x < this.scene.map.dimensions.x && selectedTilePos.y < this.scene.map.dimensions.y)); - if (this.scene.input.activePointer.isDown && !this.pointerDown) this.pointerDown = true; + // Place Tiles + switch(this.placeMode) { + case "brush": { + this.drawBrush(selectedTilePos); + break; + } + case "line": { + this.drawLine(selectedTilePos); + break; + } + case "rect": { + this.drawRect(selectedTilePos); + break; + } + } + + // Push history to HistoryManager + if (this.scene.input.activePointer.isDown && !this.pointerDown) { + this.pointerDown = true; + this.pointerPrimaryDown = this.scene.input.activePointer.leftButtonDown(); + } else if (!this.scene.input.activePointer.isDown && this.pointerDown) { if (this.manipulated.length != 0) { this.scene.history.push("tile", this.manipulated); this.manipulated = []; } this.pointerDown = false; + this.pointerPrimaryDown = false; + } + } + + drawLine(selectedTilePos: Vec2) { + if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { + if (!this.pointerDown) this.startTilePos = selectedTilePos; + + let a = new Vec2(this.startTilePos.x, this.startTilePos.y); + let b = new Vec2(selectedTilePos.x, selectedTilePos.y); + + if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) b.y = a.y; + else b.x = a.x; + + this.cursor.setPosition(b.x * 64, b.y * 64); + + this.primitives.forEach((v) => v.destroy()); + this.primitives = []; + + this.primitives.push(this.scene.add.line(0, 0, a.x + 0.5, a.y + 0.5, b.x + 0.5, b.y + 0.5, 0xffffff, 1)); + + this.primitives.forEach((v) => { + v.setOrigin(0, 0); + v.setScale(64, 64); + v.setLineWidth(0.03); + v.setDepth(300); + }); + + this.primitives.push(this.scene.add.sprite(this.startTilePos.x * 64, this.startTilePos.y * 64, "cursor") as any as Phaser.GameObjects.Line); + this.primitives[1].setOrigin(0, 0); + this.primitives[1].setScale(4, 4); + this.primitives[1].setAlpha(0.5); } + else if (!this.scene.input.mousePointer.leftButtonDown() && !this.scene.input.mousePointer.rightButtonDown() && this.pointerDown) { + let a = new Vec2(this.startTilePos.x * 64, this.startTilePos.y * 64); + let b = new Vec2(selectedTilePos.x * 64, selectedTilePos.y * 64); + + if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) b.y = a.y; + else b.x = a.x; + + let change = new Vec2(b.x - a.x, b.y - a.y); + let normalizeFactor = Math.sqrt(change.x * change.x + change.y * change.y); + change.x /= normalizeFactor; + change.y /= normalizeFactor; + + while (Math.abs(b.x - a.x) >= 1 || Math.abs(b.y - a.y) >= 1) { + this.placeTileAndPushManip(new Vec2(Math.floor(a.x / 64), Math.floor(a.y / 64)), this.pointerPrimaryDown); + a.x += change.x; + a.y += change.y; + } + + this.placeTileAndPushManip(new Vec2(b.x / 64, b.y / 64), this.pointerPrimaryDown); + this.primitives.forEach((v) => v.destroy()); + this.primitives = []; + } + } + + drawRect(selectedTilePos: Vec2) { + if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { + if (!this.pointerDown) this.startTilePos = selectedTilePos; + + let a = new Vec2(Math.min(this.startTilePos.x, selectedTilePos.x), Math.min(this.startTilePos.y, selectedTilePos.y)); + let b = new Vec2(Math.max(this.startTilePos.x, selectedTilePos.x), Math.max(this.startTilePos.y, selectedTilePos.y)); + + this.primitives.forEach((v) => v.destroy()); + this.primitives = []; + + const fac = 0.03; + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, a.y + fac, b.x + 1 - fac, a.y + fac, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, a.y + fac / 2, a.x + fac, b.y + 1 - fac / 2, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, b.y + 1 - fac, b.x + 1 - fac, b.y + 1 - fac, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, b.x + 1 - fac, a.y + fac / 2, b.x + 1 - fac, b.y + 1 - fac / 2, 0xffffff, 1)); + + this.primitives.forEach((v) => { + v.setOrigin(0, 0); + v.setScale(64, 64); + v.setLineWidth(0.03); + v.setDepth(300); + }); + } + + else if (!this.scene.input.mousePointer.leftButtonDown() && !this.scene.input.mousePointer.rightButtonDown() && this.pointerDown) { + let a = new Vec2(Math.min(this.startTilePos.x, selectedTilePos.x), Math.min(this.startTilePos.y, selectedTilePos.y)); + let b = new Vec2(Math.max(this.startTilePos.x, selectedTilePos.x), Math.max(this.startTilePos.y, selectedTilePos.y)); + + for (let i = a.x; i <= b.x; i++) { + for (let j = a.y; j <= b.y; j++) { + this.placeTileAndPushManip(new Vec2(i, j), this.pointerPrimaryDown); + } + } + + this.primitives.forEach((v) => v.destroy()); + this.primitives = []; + } + } + + drawBrush(selectedTilePos: Vec2) { if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { let change = new Vec2(this.scene.world.cursorWorld.x - this.scene.world.lastCursorWorld.x, this.scene.world.cursorWorld.y - this.scene.world.lastCursorWorld.y); @@ -47,18 +173,32 @@ class ArchitectMode { let place = new Vec2(this.scene.world.lastCursorWorld.x, this.scene.world.lastCursorWorld.y); while (Math.abs(this.scene.world.cursorWorld.x - place.x) >= 1 || Math.abs(this.scene.world.cursorWorld.y - place.y) >= 1) { - if (this.scene.map.setSolid(Math.floor(place.x / 64), Math.floor(place.y / 64), this.scene.input.mousePointer.rightButtonDown())) { - this.manipulated.push({pos: new Vec2(Math.floor(place.x / 64), Math.floor(place.y / 64)), solid: this.scene.input.mousePointer.rightButtonDown()}); - } + this.placeTileAndPushManip(new Vec2(Math.floor(place.x / 64), Math.floor(place.y / 64)), this.scene.input.mousePointer.leftButtonDown()); place.x += change.x; place.y += change.y; } - if (this.scene.map.setSolid(selectedTilePos.x, selectedTilePos.y, this.scene.input.mousePointer.rightButtonDown())) { - this.manipulated.push({pos: selectedTilePos, solid: this.scene.input.mousePointer.rightButtonDown()}); - } + + this.placeTileAndPushManip(new Vec2(selectedTilePos.x, selectedTilePos.y), this.scene.input.mousePointer.leftButtonDown()); } } + placeTileAndPushManip(manipPos: Vec2, solid: boolean) { + let wasSolid = this.scene.map.getSolid (manipPos.x, manipPos.y) != -1; + let lastPalette = this.scene.map.getPalette(manipPos.x, manipPos.y); + + + let changed = this.scene.map.setSolid(manipPos.x, manipPos.y, this.scene.activePalette, solid); + if (!changed) return; + + this.manipulated.push({ + pos: manipPos, + solid: solid, + oldSolid: wasSolid, + palette: this.scene.activePalette, + oldPalette: lastPalette + }); + } + cleanup() { if (!this.active) return; this.active = false; diff --git a/src/manip/TokenMode.ts b/src/manip/TokenMode.ts index a5de60b..12045aa 100644 --- a/src/manip/TokenMode.ts +++ b/src/manip/TokenMode.ts @@ -6,36 +6,66 @@ class TokenMode { pointerDown: boolean = false; grabOffset: Vec2; startPosition: Vec2; + currentSerialized: string = ""; constructor(scene: MainScene) { this.scene = scene; + + this.onWheel = this.onWheel.bind(this); + document.documentElement.addEventListener("wheel", this.onWheel); + this.scene.events.on('destroy', () => document.documentElement.removeEventListener("wheel", this.onWheel)); + } + + onWheel(e: WheelEvent) { + if (this.currentToken != null) { + let dir = e.deltaY > 0 ? 1 : -1; + + let frame = this.currentToken.getFrame() + dir; + if (frame < 0) frame += this.currentToken.frameCount(); + frame %= this.currentToken.frameCount(); + + this.currentToken.setFrame(frame); + } } update() { this.active = true; + let foundToHighlight = false; - for (let token of this.scene.tokens) { - if (this.scene.world.cursorWorld.x >= token.x && this.scene.world.cursorWorld.y >= token.y + for (let i = this.scene.tokens.length - 1; i >= 0; i--) { + let token = this.scene.tokens[i]; + + if (!foundToHighlight && this.scene.world.cursorWorld.x >= token.x && this.scene.world.cursorWorld.y >= token.y && this.scene.world.cursorWorld.x <= token.x + token.width && this.scene.world.cursorWorld.y <= token.y + token.height) { token.toggleOutline(true); + foundToHighlight = true; if (this.scene.input.mousePointer.leftButtonDown() && !this.pointerDown && this.currentToken == null) { this.grabOffset = new Vec2(this.scene.world.cursorWorld.x - token.x, this.scene.world.cursorWorld.y - token.y); this.startPosition = token.getPosition(); this.currentToken = token; + this.currentSerialized = this.currentToken.serialize(); this.pointerDown = true; } } - else token.toggleOutline(false); + else if (this.currentToken != token) token.toggleOutline(false); + } + if (this.currentToken == null && this.scene.input.mousePointer.leftButtonDown()) { + let token = new Token(this.scene, Math.floor(this.scene.world.cursorWorld.x / 4 / 16) * 16, + Math.floor(this.scene.world.cursorWorld.y / 4 / 16) * 16, this.scene.activeToken); + this.scene.add.existing(token); + this.scene.tokens.push(token); + this.scene.history.push("token_create", { data: token.serialize() }); } if (!this.scene.input.mousePointer.leftButtonDown() && this.pointerDown && this.currentToken != null) { - for (let token of this.scene.tokens) token.toggleOutline(false); + for (let token of this.scene.tokens) if (token != this.currentToken) token.toggleOutline(false); - if (this.currentToken.getPosition().x != this.startPosition.x || this.currentToken.getPosition().y != this.startPosition.y) - this.scene.history.push("token_move", { start: this.startPosition, end: this.currentToken.getPosition(), token: this.currentToken }); + if (JSON.stringify(this.currentToken.serialize()) != JSON.stringify(this.currentSerialized)) + this.scene.history.push("token_modify", { old: this.currentSerialized, new: this.currentToken.serialize() }); this.currentToken = null; + this.currentSerialized = ""; this.pointerDown = false; } diff --git a/src/scene/GetAssetsScene.ts b/src/scene/GetAssetsScene.ts new file mode 100644 index 0000000..80cc417 --- /dev/null +++ b/src/scene/GetAssetsScene.ts @@ -0,0 +1,45 @@ +class GetAssetsScene extends Phaser.Scene { + constructor() { + super({key: "GetAssetsScene"}); + } + + preload(): void { + this.cameras.main.setBackgroundColor("#6a655a"); + + this.load.image('splash', '/res/splash.png'); + this.load.text("assets", "res/_assets.txt"); + } + + create(): void { + let assets = this.cache.text.get("assets"); + let lines: string[] = assets.split("\n"); + + let assetsParsed = ""; + let prefixes = {}; + + lines.forEach((v: string) => { + if (v.substr(0, "FOLDERPREFIX".length) == "FOLDERPREFIX") { + let tokens = v.split(" "); + prefixes[tokens[1]] = tokens[2]; + return; + } + if (v.length == 0) return; + + let slash = v.indexOf('/'); + + let prefix = ""; + if (slash != -1 && prefixes[v.substr(0, slash)] != undefined) prefix = prefixes[v.substr(0, slash)]; + + if (slash == -1) assetsParsed += `${v.split(" ")[0]} ${v}\n`; + else assetsParsed += `${prefix}${v.substring(slash + 1, v.length).split(" ")[0]} ${v}\n`; + }); + + this.cache.text.remove("assets"); + this.cache.text.add("assets", assetsParsed); + + this.game.scene.start('LoadScene'); + this.game.scene.stop('GetAssetsScene'); + this.game.scene.swapPosition('LoadScene', 'GetAssetsScene'); + } +} + diff --git a/src/scene/LoadScene.ts b/src/scene/LoadScene.ts new file mode 100644 index 0000000..f5327d7 --- /dev/null +++ b/src/scene/LoadScene.ts @@ -0,0 +1,37 @@ +class LoadScene extends Phaser.Scene { + constructor() { + super({key: "LoadScene"}); + } + + preload(): void { + this.cameras.main.setBackgroundColor("#6a655a"); + + this.add.sprite(this.cameras.main.width / 2, this.cameras.main.height /2, "splash"); + + this.load.bitmapFont('font1x', '/res/font/font1.png', '/res/font/font1.fnt'); + this.load.bitmapFont('font2x', '/res/font/font2.png', '/res/font/font2.fnt'); + this.load.bitmapFont('font3x', '/res/font/font3.png', '/res/font/font3.fnt'); + + for (let s of this.cache.text.get("assets").split("\n")) { + let tokens = s.split(" "); + if (tokens.length == 2) this.load.image(tokens[0], "/res/" + tokens[1] + ".png"); + else if (tokens.length == 4) this.load.spritesheet(tokens[0], "/res/" + tokens[1] + ".png", {frameWidth: parseInt(tokens[2]), frameHeight: parseInt(tokens[3])}); + } + + for (let t of TOKENS) { + if (t.split_by != undefined) this.load.spritesheet(t.key, t.file + ".png", {frameWidth: t.split_by, frameHeight: t.split_by}); + else this.load.image(t.key, t.file + ".png"); + } + } + + create(): void { + this.cache.text.remove("assets"); + + setTimeout(() => { + this.game.scene.start('MainScene'); + this.game.scene.stop('LoadScene'); + this.game.scene.swapPosition('MainScene', 'LoadScene'); + }, 50) + } +} + diff --git a/src/MainScene.ts b/src/scene/MainScene.ts similarity index 73% rename from src/MainScene.ts rename to src/scene/MainScene.ts index bbc9e5c..64182e9 100644 --- a/src/MainScene.ts +++ b/src/scene/MainScene.ts @@ -14,7 +14,11 @@ class MainScene extends Phaser.Scene { architect: ArchitectMode; token: TokenMode; + chat: Chat; + timeHoldingHistoryKey: number = 0; + activePalette: number = 0; + activeToken: string = "tkn_treasure"; snapKey: Phaser.Input.Keyboard.Key; modifierKey: Phaser.Input.Keyboard.Key; @@ -26,17 +30,11 @@ class MainScene extends Phaser.Scene { constructor() { super({key: "MainScene"}); } preload(): void { - this.load.image("cursor", "res/cursor.png"); - - for (let i = 1; i <= this.TILESET_COUNT; i++) - this.load.image("tileset_" + i, "res/tileset_" + i + ".png"); - - this.load.image("grid_tile", "res/grid.png"); - - this.load.image("player", "res/player.png"); - - this.load.spritesheet("ui_mode_switch", "res/button_edit_mode.png", {frameWidth: 39, frameHeight: 18}); - this.load.spritesheet("ui_history_manipulation", "res/button_undo_redo.png", {frameWidth: 39, frameHeight: 18}); + window.addEventListener('resize', () => { + let frame = document.getElementById("game"); + this.game.scale.resize(frame.offsetWidth, frame.offsetHeight); + this.chat.x = -10000 + this.cameras.main.width - 309; + }); } create(): void { @@ -47,13 +45,13 @@ class MainScene extends Phaser.Scene { this.undoRedoKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z); this.redoKeyWin = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Y); - this.switchModeKey.addListener('down', () => { this.mode = this.mode == 0 ? 1 : 0 }); - this.undoRedoKey.addListener('down', () => { + this.switchModeKey.addListener("down", () => { this.mode = this.mode == 0 ? 1 : 0 }); + this.undoRedoKey.addListener("down", () => { if (!this.modifierKey.isDown) return; this.timeHoldingHistoryKey = 0; this.snapKey.isDown ? this.history.redo() : this.history.undo(); }); - this.redoKeyWin.addListener('down', () => { + this.redoKeyWin.addListener("down", () => { this.timeHoldingHistoryKey = 0; if (!this.modifierKey.isDown) return; this.history.redo(); @@ -65,25 +63,23 @@ class MainScene extends Phaser.Scene { this.world = new WorldView(this); this.ui = new UIView(this); + this.ui.createElements(); + + this.chat = new Chat(this, -10000 + this.cameras.main.width - 309, this.cameras.main.height - 9); + this.add.existing(this.chat); this.map = new TileMap("gameMap", this, 300, 300); - this.map.fillMap(10); this.architect = new ArchitectMode(this); this.token = new TokenMode(this); - let edit = new UIModeSwitchButton(this, 1, 1); - this.ui.o.add(edit); - - let history = new UIHistoryManipulation(this, 16, 1); - this.ui.o.add(history); - - this.tokens.push(new Token(this, 64, 64, "player")); + let tileset = new TilesetPatcher(this); } update(time: number, delta: number): void { this.world.update(); this.ui.update(); + this.chat.update(); if ((this.redoKeyWin.isDown || this.undoRedoKey.isDown) && this.modifierKey.isDown) { if (this.timeHoldingHistoryKey > 12 && this.timeHoldingHistoryKey % 3 == 0) { diff --git a/src/ui/UIComponent.ts b/src/ui/UIComponent.ts index 72472c4..a7261e7 100644 --- a/src/ui/UIComponent.ts +++ b/src/ui/UIComponent.ts @@ -4,6 +4,7 @@ class UIComponent extends Phaser.GameObjects.Sprite { this.setOrigin(0, 0); this.setScale(3, 3); this.setPos(x * 3, y * 3); + this.setActive(true); this.scene.add.existing(this); } diff --git a/src/ui/UIContainer.ts b/src/ui/UIContainer.ts new file mode 100644 index 0000000..0c4ea3b --- /dev/null +++ b/src/ui/UIContainer.ts @@ -0,0 +1,33 @@ +class UIContainer extends Phaser.GameObjects.Container { + intersects: Phaser.GameObjects.Sprite[] = []; + + constructor(scene: Phaser.Scene, x: number, y: number) { + super(scene, x, y); + this.setPos(x * 3, y * 3); + this.setActive(true); + + this.scene.add.existing(this); + } + + setPos(x: number, y: number) { + this.setPosition(x * 3, y * 3); + } + + mouseIntersects(): boolean { + for (let i of this.list) { + if ((i as UIComponent).mouseIntersects != null) if ((i as UIComponent).mouseIntersects()) return true; + } + for (let i of this.intersects) { + let pointer = this.scene.input.mousePointer; + if (pointer.x >= this.x + i.x && pointer.y >= this.y + i.y + && pointer.x <= this.x + i.x + i.width * i.scaleX && pointer.y <= this.y + i.y + i.height * i.scaleY) + return true; + } + return false; + } + + mousePos(): Vec2 { + let pointer = this.scene.input.mousePointer; + return new Vec2(Math.round((pointer.x - this.x)/3), Math.round((pointer.y - this.y)/3)); + } +} diff --git a/src/ui/UISideMenuButton.ts b/src/ui/UISideMenuButton.ts new file mode 100644 index 0000000..3e547ea --- /dev/null +++ b/src/ui/UISideMenuButton.ts @@ -0,0 +1,21 @@ +class UISideMenuButton extends UIComponent { + scene: MainScene; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y, "ui_button_side_menu"); + this.scene = scene; + this.setActive(true); + } + + update() { + if (this.mouseIntersects()) { + if (this.scene.input.mousePointer.leftButtonDown()) { + this.setFrame(2); + } + else this.setFrame(1); + } + else { + this.setFrame(0); + } + } +} diff --git a/src/ui/UISidebar.ts b/src/ui/UISidebar.ts new file mode 100644 index 0000000..507df41 --- /dev/null +++ b/src/ui/UISidebar.ts @@ -0,0 +1,96 @@ +class UISidebar extends UIContainer { + scene: MainScene; + + backgrounds: Phaser.GameObjects.Sprite[] = []; + + activeSpriteCursor: Phaser.GameObjects.Sprite; + hoverSpriteCursor: Phaser.GameObjects.Sprite; + + elems: any[] = []; + sprites: any[] = []; + + hoveredElem: Vec2 | null = null; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + this.scene = scene; + + for (let i = 0; i < 15; i++) { + let background = new Phaser.GameObjects.Sprite(this.scene, 0, 21 * 3 * i, "ui_sidebar_bg", 1); + background.setScale(3); + background.setOrigin(0, 0); + + this.backgrounds.push(background); + this.list.push(background); + } + + this.activeSpriteCursor = new Phaser.GameObjects.Sprite(this.scene, 9, 9, "ui_sidebar_cursor"); + this.activeSpriteCursor.setScale(3); + this.activeSpriteCursor.setOrigin(0); + this.list.push(this.activeSpriteCursor); + + this.hoverSpriteCursor = new Phaser.GameObjects.Sprite(this.scene, 3, 3, "ui_sidebar_cursor"); + this.hoverSpriteCursor.setScale(3); + this.hoverSpriteCursor.setOrigin(0); + this.hoverSpriteCursor.setAlpha(0.35); + this.hoverSpriteCursor.setVisible(false); + this.list.push(this.hoverSpriteCursor); + } + + mouseIntersects(): boolean { + return (this.mousePos().x < 69); + } + + update() { + let hovered = undefined; + + if (this.mouseIntersects()) { + if (this.mousePos().x % 21 >= 4 && this.mousePos().y % 21 >= 4) { + let mousePos = this.mousePos(); + + let x = Math.floor(mousePos.x / 21); + let y = Math.floor(mousePos.y / 21); + + hovered = this.sprites[x + y * 3]; + + if (hovered != undefined) { + this.hoverSpriteCursor.setVisible(true); + this.hoverSpriteCursor.setPosition(9 + x * 21 * 3, 9 + y * 21 * 3); + } + else { + this.hoverSpriteCursor.setVisible(false); + return; + } + + if (hovered == undefined && this.hoveredElem != null) { + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + this.hoveredElem = null; + return; + } + + if (this.hoveredElem != null && this.hoveredElem.x != x && this.hoveredElem.y != y) + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + + this.elemHover(x, y); + this.hoveredElem = new Vec2(x, y); + + if (this.scene.input.mousePointer.leftButtonDown()) { + this.activeSpriteCursor.setPosition(9 + x * 21 * 3, 9 + y * 21 * 3); + this.elemClick(x, y); + } + } + else { + if (this.hoveredElem != null) + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + this.hoveredElem = null; + this.hoverSpriteCursor.setVisible(false); + } + } + else this.hoverSpriteCursor.setVisible(false); + } + + elemHover(x: number, y: number): void {} + elemUnhover(x: number, y: number): void {} + + elemClick(x: number, y: number): void {} +} diff --git a/src/ui/UITileSelector.ts b/src/ui/UITileSelector.ts new file mode 100644 index 0000000..213cc69 --- /dev/null +++ b/src/ui/UITileSelector.ts @@ -0,0 +1,58 @@ +class UITileSelector extends UIContainer { + scene: MainScene; + + background: Phaser.GameObjects.Sprite; + tileSprites: Phaser.GameObjects.Sprite[]; + + tiles: number[] = []; + selectSprite: Phaser.GameObjects.Sprite; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + this.scene = scene; + + this.background = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "ui_quick_selector"); + this.background.setScale(3, 3); + this.background.setOrigin(0, 0); + this.intersects.push(this.background); + this.add(this.background); + + this.selectSprite = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "cursor"); + this.selectSprite.setScale(3, 3); + this.selectSprite.setOrigin(0, 0); + this.add(this.selectSprite); + this.positionSelect(0); + } + + positionSelect(slot: number) { + this.selectSprite.setPosition(12, 18 + slot*60); + } + + update() { + if (this.mouseIntersects() && this.scene.input.mousePointer.leftButtonDown()) { + let mousePos = this.mousePos(); + if (mousePos.x < 4 || mousePos.x > 4 + 16) return; + + mousePos.y -= 6; + if (mousePos.y % 20 > 16) return; + + let slot = Math.floor(mousePos.y / 20); + if (slot < 0 || slot >= this.tiles.length) return; + this.scene.activePalette = this.tiles[slot]; + this.positionSelect(slot); + } + } + + addTile(tile: number) { + let pos = this.tiles.length; + this.tiles.push(tile); + + let spr = new Phaser.GameObjects.Sprite(this.scene, 12 - 22*2, 18 - 22*2 + pos*60, "tileset_" + tile); + spr.setOrigin(0, 0); + spr.setCrop(22, 22, 24, 24); + spr.setScale(2); + this.add(spr); + this.sendToBack(spr); + this.sendToBack(this.background); + } +} diff --git a/src/ui/UITileSidebar.ts b/src/ui/UITileSidebar.ts new file mode 100644 index 0000000..72056fb --- /dev/null +++ b/src/ui/UITileSidebar.ts @@ -0,0 +1,31 @@ +class UITileSidebar extends UISidebar { + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + } + + elemClick(x: number, y: number): void { + this.scene.activePalette = this.elems[x + y * 3]; + } + + addPalette(tile: number) { + let p = this.elems.length; + let x = p % 3; + let y = Math.floor(p / 3); + this.elems.push(tile); + + let spr = new Phaser.GameObjects.Sprite(this.scene, 12 + x * 21 * 3 - 22 * 2, 12 + y * 21 * 3 - 22 * 2, "tileset_" + tile); + spr.setOrigin(0, 0); + spr.setCrop(21, 21, 26, 26); + spr.setScale(2); + this.sprites.push(spr); + this.list.push(spr); + let spr2 = new Phaser.GameObjects.Sprite(this.scene, 9 + x * 21 * 3, 9 + y * 21 * 3, "ui_sidebar_overlay"); + spr2.setScale(3); + spr2.setOrigin(0, 0); + this.list.push(spr2); + + this.bringToTop(this.hoverSpriteCursor); + this.bringToTop(this.activeSpriteCursor); + } +} diff --git a/src/ui/UITokenSelector.ts b/src/ui/UITokenSelector.ts new file mode 100644 index 0000000..e1f8505 --- /dev/null +++ b/src/ui/UITokenSelector.ts @@ -0,0 +1,57 @@ +class UITokenSelector extends UIContainer { + scene: MainScene; + + background: Phaser.GameObjects.Sprite; + tokenSprites: Phaser.GameObjects.Sprite[]; + + tokens: string[] = []; + selectSprite: Phaser.GameObjects.Sprite; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + this.scene = scene; + + this.background = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "ui_quick_selector"); + this.background.setScale(3, 3); + this.background.setOrigin(0, 0); + this.intersects.push(this.background); + this.add(this.background); + + this.selectSprite = new Phaser.GameObjects.Sprite(this.scene, 0, 0, "cursor"); + this.selectSprite.setScale(3, 3); + this.selectSprite.setOrigin(0, 0); + this.add(this.selectSprite); + this.positionSelect(0); + } + + positionSelect(slot: number) { + this.selectSprite.setPosition(12, 18 + slot*60); + } + + update() { + if (this.mouseIntersects() && this.scene.input.mousePointer.leftButtonDown()) { + let mousePos = this.mousePos(); + if (mousePos.x < 4 || mousePos.x > 4 + 16) return; + + mousePos.y -= 6; + if (mousePos.y % 20 > 16) return; + + let slot = Math.floor(mousePos.y / 20); + if (slot < 0 || slot >= this.tokens.length) return; + this.scene.activeToken = this.tokens[slot]; + this.positionSelect(slot); + } + } + + addToken(sprite: string) { + let pos = this.tokens.length; + this.tokens.push(sprite); + + let spr = new Phaser.GameObjects.Sprite(this.scene, 12 - 3, 18 - 3 + pos*60, sprite); + spr.setOrigin(0, 0); + spr.setScale(3); + this.add(spr); + this.sendToBack(spr); + this.sendToBack(this.background); + } +} diff --git a/src/ui/UITokenSidebar.ts b/src/ui/UITokenSidebar.ts new file mode 100644 index 0000000..44562e8 --- /dev/null +++ b/src/ui/UITokenSidebar.ts @@ -0,0 +1,47 @@ +class UITokenSidebar extends UISidebar { + + spinTimer: number = 0; + + constructor(scene: MainScene, x: number, y: number) { + super(scene, x, y); + } + + elemHover(x: number, y: number): void { + let hoveredToken = this.sprites[x + y * 3] as Token; + + this.spinTimer++; + if (this.spinTimer > 20) { + let frame = hoveredToken.getFrame() + 1; + frame %= hoveredToken.frameCount(); + hoveredToken.setFrame(frame); + this.spinTimer = 0; + } + } + + elemUnhover(x: number, y: number): void { + this.sprites.forEach(t => t.setFrame(0)); + } + + elemClick(x: number, y: number): void { + this.scene.activeToken = this.elems[x + y * 3]; + } + + addToken(sprite: string) { + let p = this.elems.length; + let x = p % 3; + let y = Math.floor(p / 3); + this.elems.push(sprite); + + if (x == 0) this.backgrounds[y].setFrame(0); + + let token = new Token(this.scene, 0, 0, sprite); + Phaser.GameObjects.Sprite.prototype.setPosition.call(token, 12 + x * 21 * 3, 12 + y * 21 * 3); + token.setScale(3 / 4); + + this.sprites.push(token); + this.list.push(token); + + this.bringToTop(this.activeSpriteCursor); + this.bringToTop(this.hoverSpriteCursor); + } +} diff --git a/tool.js b/tool.js index c2d0748..d1e7246 100644 --- a/tool.js +++ b/tool.js @@ -11,6 +11,124 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); +var Chat = /** @class */ (function (_super) { + __extends(Chat, _super); + function Chat(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.messages = []; + _this.textInput = new TextInput(scene, 0, 0); + _this.list.push(_this.textInput); + _this.messageContainer = new Phaser.GameObjects.Container(scene, 0, 0); + _this.list.push(_this.messageContainer); + return _this; + } + Chat.prototype.update = function () { + this.textInput.y = -this.textInput.getHeight(); + this.messageContainer.y = this.textInput.y - 3; + }; + Chat.prototype.pushMessage = function (message) { + this.messages.unshift(new ChatBox(this.scene, 0, 0, message)); + this.messageContainer.list.push(this.messages[0]); + this.scene.tweens.add({ + targets: this.messages[0], + alpha: { from: 0, to: 1 }, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + this.reflowMessages(); + }; + Chat.prototype.reflowMessages = function () { + var y = 0; + for (var _i = 0, _a = this.messages; _i < _a.length; _i++) { + var message = _a[_i]; + y -= message.getHeight() + 9; + if (y + message.getHeight() < -400) { + this.scene.tweens.add({ + targets: message, + alpha: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + this.scene.tweens.add({ + targets: message, + y: y, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + } + }; + return Chat; +}(Phaser.GameObjects.Container)); +var ChatBox = /** @class */ (function (_super) { + __extends(ChatBox, _super); + function ChatBox(scene, x, y, str, tex) { + var _this = _super.call(this, scene, x, y) || this; + _this.texture = "ui_text_box"; + _this.FONT_SIZE = 4.3; + _this.chatboxHeight = 0; + _this.str = str; + if (tex != undefined) + _this.texture = tex; + _this.setText(str); + return _this; + } + ChatBox.prototype.setText = function (text) { + this.list.forEach(function (e) { return e.destroy(); }); + this.list = []; + this.str = text; + var testObj = new Phaser.GameObjects.BitmapText(this.scene, 15, 4, "font2x", "AB", this.FONT_SIZE, 0); + var letterWidth = testObj.getTextBounds().global.width / 2; + var maxLetters = 95 / letterWidth; + var split = this.str.split(/( )/g); + var lines = []; + function nextLine() { + var newLine = ""; + while ((newLine + " " + split[0]).length < maxLetters && split.length) + newLine += split.shift(); + lines.push(newLine.trim()); + if (split.length) + nextLine(); + } + nextLine(); + var top = new Phaser.GameObjects.Sprite(this.scene, 0, 0, this.texture, 0); + top.setScale(3, 3); + top.setOrigin(0, 0); + top.setAlpha(0.6); + this.list.push(top); + var i = 0; + for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) { + var line = lines_1[_i]; + var elem = new Phaser.GameObjects.BitmapText(this.scene, 12, 7 + i * 18, "font2x", line, this.FONT_SIZE, 0); + elem.setScale(3, 3); + elem.setOrigin(0, 0); + this.list.push(elem); + i++; + } + var lastElem = this.list[this.list.length - 1]; + var height = Math.max(lastElem.y + lastElem.getTextBounds().global.height - 36, 2); + var middle = new Phaser.GameObjects.Sprite(this.scene, 0, 18, "ui_text_box", 1); + middle.setScale(3, height / 6); + middle.setOrigin(0, 0); + middle.setAlpha(0.6); + this.list.push(middle); + this.sendToBack(middle); + var bottom = new Phaser.GameObjects.Sprite(this.scene, 0, height + 18, this.texture, 2); + bottom.setScale(3, 3); + bottom.setOrigin(0, 0); + bottom.setAlpha(0.6); + this.list.push(bottom); + this.sendToBack(bottom); + this.chatboxHeight = height + 18 * 2; + }; + ChatBox.prototype.getHeight = function () { + return this.chatboxHeight; + }; + return ChatBox; +}(Phaser.GameObjects.Container)); var HistoryElement = /** @class */ (function () { function HistoryElement(scene, type, data) { this.scene = scene; @@ -18,27 +136,67 @@ var HistoryElement = /** @class */ (function () { this.data = data; } HistoryElement.prototype.undo = function () { + console.log("Undo", this.type); if (this.type == "tile") { for (var _i = 0, _a = this.data; _i < _a.length; _i++) { var tile = _a[_i]; - this.scene.map.setSolid(tile.pos.x, tile.pos.y, !tile.solid); + this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.oldPalette, tile.oldSolid); } } - else if (this.type == "token_move") { + else if (this.type == "token_modify") { var data = this.data; - data.token.setPosition(data.start.x, data.start.y); + var uuid = JSON.parse(this.data.old).uuid; + for (var _b = 0, _c = this.scene.tokens; _b < _c.length; _b++) { + var token_1 = _c[_b]; + if (token_1.uuid == uuid) { + token_1.loadSerializedData(this.data.old); + return; + } + } + var token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.old); + this.scene.add.existing(token); + this.scene.tokens.push(token); + } + else if (this.type == "token_create") { + var uuid = JSON.parse(this.data.data).uuid; + for (var i = 0; i < this.scene.tokens.length; i++) { + if (this.scene.tokens[i].uuid == uuid) { + this.scene.tokens[i].destroy(); + this.scene.tokens.splice(i, 1); + } + } } }; HistoryElement.prototype.redo = function () { + console.log("Redo", this.type); if (this.type == "tile") { for (var _i = 0, _a = this.data; _i < _a.length; _i++) { var tile = _a[_i]; - this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.solid); + this.scene.map.setSolid(tile.pos.x, tile.pos.y, tile.palette, tile.solid); } } - else if (this.type == "token_move") { + else if (this.type == "token_modify") { var data = this.data; - data.token.setPosition(data.end.x, data.end.y); + var uuid = JSON.parse(this.data.old).uuid; + for (var _b = 0, _c = this.scene.tokens; _b < _c.length; _b++) { + var token_2 = _c[_b]; + if (token_2.uuid == uuid) { + token_2.loadSerializedData(this.data.new); + return; + } + } + var token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.new); + this.scene.add.existing(token); + this.scene.tokens.push(token); + } + else if (this.type == "token_create") { + var data = JSON.parse(this.data.data); + var token = new Token(this.scene, 0, 0, ""); + token.loadSerializedData(this.data.data); + this.scene.add.existing(token); + this.scene.tokens.push(token); } }; return HistoryElement; @@ -67,175 +225,6 @@ var HistoryManager = /** @class */ (function () { }; return HistoryManager; }()); -// class IntroScene extends Phaser.Scene { -// stars: Star[] = []; -// pickups: Pickup[] = []; -// spark: Spark; -// text: Phaser.GameObjects.Text; -// speed: number; -// angleChange: number; -// controllingSpark: boolean; -// animationRange: number; -// starAngle: number; -// collided: boolean; -// canDie: boolean; -// constructor() { -// super({key: "IntroScene"}); -// } -// preload(): void { -// this.load.spritesheet("star", "res/star.png", {frameWidth: 8, frameHeight: 8, startFrame: 0, endFrame: 16}); -// this.load.spritesheet("spark", "res/spark.png", {frameWidth: 16, frameHeight: 16, startFrame: 0, endFrame: 64}); -// this.load.spritesheet("pickup", "res/pickup.png", {frameWidth: 16, frameHeight: 16}); -// } -// create(): void { -// this.stars = []; -// this.pickups = []; -// this.speed = 0.25; -// this.angleChange = 0.001; -// this.controllingSpark = false; -// this.animationRange = -1; -// this.starAngle = -(Math.PI / 1.5); -// this.collided = false; -// this.canDie = false; -// //@ts-ignore -// $("#game").removeClass('active'); -// for (let i = 0; i < 200; i++) { -// let x = Math.round(Math.random() * (this.cameras.main.width / 4)); -// let y = Math.round(Math.random() * (this.cameras.main.height / 4)); -// this.stars.push(new Star(this, x, y)); -// } -// for (let i = 0; i < 8; i++) { -// let x = Math.round(Math.random() * (this.cameras.main.width / 4)); -// let y = Math.round(Math.random() * (this.cameras.main.height / 4)); -// this.pickups.push(new Pickup(this, x, y)); -// } -// this.spark = new Spark(this, this.cameras.main.width / 2, this.cameras.main.height / 2); -// // this.text = this.add.text(4, 4, this.collisions.toString()); -// } -// update(time: number, delta: number): void { -// if (this.input.mousePointer.primaryDown && !this.controllingSpark) { -// if (this.input.mousePointer.x > this.cameras.main.width / 2 - 16 -// && this.input.mousePointer.x < this.cameras.main.width / 2 + 16 -// && this.input.mousePointer.y > this.cameras.main.height / 2 - 16 -// && this.input.mousePointer.y < this.cameras.main.height / 2 + 16) { -// this.controllingSpark = true; -// this.canDie = true; -// //@ts-ignore -// $("#game").addClass('active'); -// this.animationRange = 0; -// } -// } -// if (this.controllingSpark) { -// this.spark.setPosition(Math.round(this.input.mousePointer.x / 4) * 4, Math.round(this.input.mousePointer.y / 4) * 4); -// } -// if (this.animationRange != -1) { -// if (!this.collided) { -// this.fadeIn(this.animationRange*this.cameras.main.width); -// this.animationRange += 0.02; -// if (this.animationRange >= 1) this.animationRange = -1; -// } -// else { -// this.fadeOut(this.animationRange*this.cameras.main.width); -// this.animationRange -= 0.05; -// if (this.animationRange <= 0) this.scene.restart(); -// } -// } -// if (this.speed < 5) { -// if (this.controllingSpark) { -// this.starAngle += this.angleChange; -// this.speed *= 1.001; -// this.angleChange *= 1.000005; -// } -// } -// else { -// this.controllingSpark = false; -// this.canDie = false; -// this.starAngle = Math.PI * 1.5; -// this.speed *= 1.02; -// if (this.speed < 10) this.spark.moveToCenter(); -// if (this.speed > 10) this.spark.y += this.speed; -// if (this.speed > 15) this.spark.explode(); -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(15, 11, 31), new Phaser.Display.Color(255, 255, 255), 30, Math.min(Math.max(this.speed - 10, 0), 30)); -// this.cameras.main.setBackgroundColor(hexColor); -// if (this.speed >= 60) { -// this.game.scene.start('MainScene'); -// this.game.scene.stop('IntroScene'); -// this.game.scene.swapPosition('MainScene', 'IntroScene'); -// return; -// } -// } -// let yOff = Math.sin(this.starAngle); -// let xOff = Math.cos(this.starAngle); -// for (let star of this.stars) { -// star.push(xOff * this.speed, yOff * this.speed); -// star.stayOnScreen(); -// } -// for (let pickup of this.pickups) { -// pickup.push(xOff * this.speed, yOff * this.speed); -// if (this.canDie) { -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.spark.x), 2) -// + Math.pow(Math.abs(pickup.y - this.spark.y), 2)); -// if (distance < 32 && !this.collided) { -// this.collided = true; -// this.animationRange = 0.7; -// this.controllingSpark = false; -// this.spark.explode(); -// } -// } -// } -// } -// fadeIn(range: number) { -// for (let star of this.stars) { -// let distance = Math.sqrt(Math.pow(Math.abs(star.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(star.y - this.cameras.main.height/2), 2)); -// if (range > distance && range < distance + 200) star.fadeIn(); -// if (range > distance + 200) star.fadeReg(); -// } -// for (let pickup of this.pickups) { -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(pickup.y - this.cameras.main.height/2), 2)); -// if (range + 200 > distance) pickup.makeExists(); -// } -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(0, 0, 0), new Phaser.Display.Color(15, 11, 31), 1, this.animationRange); -// this.cameras.main.setBackgroundColor(hexColor); -// } -// fadeOut(range: number) { -// for (let star of this.stars) { -// let distance = Math.sqrt(Math.pow(Math.abs(star.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(star.y - this.cameras.main.height/2), 2)); -// if (range > distance && range < distance + 200) star.fadeIn(); -// if (range < distance) star.fadeOut(); -// } -// for (let i = 0; i < this.pickups.length; i++) { -// let pickup = this.pickups[i]; -// let distance = Math.sqrt(Math.pow(Math.abs(pickup.x - this.cameras.main.width/2), 2) -// + Math.pow(Math.abs(pickup.y - this.cameras.main.height/2), 2)); -// if (range - 200 < distance) { -// pickup.setAlpha(0); -// } -// } -// let hexColor = Phaser.Display.Color.Interpolate.ColorWithColor(new Phaser.Display.Color(0, 0, 0), new Phaser.Display.Color(15, 11, 31), 0.8, this.animationRange); -// this.cameras.main.setBackgroundColor(hexColor); -// } -// } -var LoadScene = /** @class */ (function (_super) { - __extends(LoadScene, _super); - function LoadScene() { - return _super.call(this, { key: "LoadScene" }) || this; - } - LoadScene.prototype.preload = function () { - this.cameras.main.setBackgroundColor("#300"); - //TODO: Find out why loaded assets aren't propogating - }; - LoadScene.prototype.create = function () { - this.game.scene.start('MainScene'); - this.game.scene.stop('LoadScene'); - this.game.scene.swapPosition('MainScene', 'LoadScene'); - }; - LoadScene.prototype.update = function (time, delta) { - }; - return LoadScene; -}(Phaser.Scene)); /// var game; window.onload = function () { @@ -247,7 +236,7 @@ window.onload = function () { parent: "game", backgroundColor: "#000000", antialias: false, - scene: [MainScene, LoadScene], + scene: [GetAssetsScene, LoadScene, MainScene], physics: { default: "arcade", arcade: { @@ -269,108 +258,44 @@ var DNDMapper = /** @class */ (function (_super) { } return DNDMapper; }(Phaser.Game)); -var MainScene = /** @class */ (function (_super) { - __extends(MainScene, _super); - function MainScene() { - var _this = _super.call(this, { key: "MainScene" }) || this; - _this.TILESET_COUNT = 3; - _this.mode = 0; - _this.tokens = []; - _this.timeHoldingHistoryKey = 0; - return _this; - } - MainScene.prototype.preload = function () { - this.load.image("cursor", "res/cursor.png"); - for (var i = 1; i <= this.TILESET_COUNT; i++) - this.load.image("tileset_" + i, "res/tileset_" + i + ".png"); - this.load.image("grid_tile", "res/grid.png"); - this.load.image("player", "res/player.png"); - this.load.spritesheet("ui_mode_switch", "res/button_edit_mode.png", { frameWidth: 39, frameHeight: 18 }); - this.load.spritesheet("ui_history_manipulation", "res/button_undo_redo.png", { frameWidth: 39, frameHeight: 18 }); - }; - MainScene.prototype.create = function () { - var _this = this; - this.snapKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); - this.modifierKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.CTRL); - this.switchModeKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.TAB); - this.undoRedoKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z); - this.redoKeyWin = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Y); - this.switchModeKey.addListener('down', function () { _this.mode = _this.mode == 0 ? 1 : 0; }); - this.undoRedoKey.addListener('down', function () { - if (!_this.modifierKey.isDown) - return; - _this.timeHoldingHistoryKey = 0; - _this.snapKey.isDown ? _this.history.redo() : _this.history.undo(); - }); - this.redoKeyWin.addListener('down', function () { - _this.timeHoldingHistoryKey = 0; - if (!_this.modifierKey.isDown) - return; - _this.history.redo(); - }); - this.game.renderer.addPipeline('outline', new OutlinePipeline(this.game)); - this.history = new HistoryManager(this); - this.world = new WorldView(this); - this.ui = new UIView(this); - this.map = new TileMap("gameMap", this, 300, 300); - this.map.fillMap(10); - this.architect = new ArchitectMode(this); - this.token = new TokenMode(this); - var edit = new UIModeSwitchButton(this, 1, 1); - this.ui.o.add(edit); - var history = new UIHistoryManipulation(this, 16, 1); - this.ui.o.add(history); - this.tokens.push(new Token(this, 64, 64, "player")); - }; - MainScene.prototype.update = function (time, delta) { - this.world.update(); - this.ui.update(); - if ((this.redoKeyWin.isDown || this.undoRedoKey.isDown) && this.modifierKey.isDown) { - if (this.timeHoldingHistoryKey > 12 && this.timeHoldingHistoryKey % 3 == 0) { - if (this.redoKeyWin.isDown) - this.history.redo(); - else if (this.snapKey.isDown) - this.history.redo(); - else - this.history.undo(); - } - this.timeHoldingHistoryKey++; - } - else { - this.timeHoldingHistoryKey = 0; - } - if (this.mode == 0) { - if (this.ui.uiActive) - this.architect.cleanup(); - else { - this.architect.update(); - this.token.cleanup(); - } - } - else { - if (this.ui.uiActive) - this.token.cleanup(); - else { - this.token.update(); - this.architect.cleanup(); - } - } - }; - return MainScene; -}(Phaser.Scene)); var OutlinePipeline = /** @class */ (function (_super) { __extends(OutlinePipeline, _super); function OutlinePipeline(game) { var _this = this; var config = { game: game, renderer: game.renderer, - fragShader: "\n\t\t\tprecision mediump float;\n\t\t\tuniform sampler2D uMainSampler;\n\t\t\tvarying vec2 outTexCoord;\n\t\t\tvoid main(void) {\n\t\t\t\tvec4 color = texture2D(uMainSampler, outTexCoord);\n\t\t\t\tvec4 colorU = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y - 0.055));\n\t\t\t\tvec4 colorD = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y + 0.055));\n\t\t\t\tvec4 colorL = texture2D(uMainSampler, vec2(outTexCoord.x + 0.055, outTexCoord.y));\n\t\t\t\tvec4 colorR = texture2D(uMainSampler, vec2(outTexCoord.x - 0.055, outTexCoord.y));\n\t\t\t\t\n\t\t\t\tgl_FragColor = color;\n\t\t\t\t\n\t\t\t\tif (color.a == 0.0 && (colorU.a != 0.0 || colorD.a != 0.0 || colorL.a != 0.0 || colorR.a != 0.0) ) {\n\t\t\t\t\tgl_FragColor = vec4(1.0, 1.0, 1.0, .2);\n\t\t\t\t}\n\t\t\t}" + fragShader: "\n\t\t\tprecision mediump float;\n\n\t\t\tuniform sampler2D uMainSampler;\n\t\t\tuniform float tex_size;\n\n\t\t\tvarying vec2 outTexCoord;\n\t\t\t\n\t\t\tvoid main(void) {\n\t\t\t\tfloat factor = 1.0 / tex_size;\n\n\t\t\t\tvec4 color = texture2D(uMainSampler, outTexCoord);\n\t\t\t\tvec4 colorU = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y + factor));\n\t\t\t\tvec4 colorD = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y - factor));\n\t\t\t\tvec4 colorL = texture2D(uMainSampler, vec2(outTexCoord.x + factor, outTexCoord.y));\n\t\t\t\tvec4 colorR = texture2D(uMainSampler, vec2(outTexCoord.x - factor, outTexCoord.y));\n\t\t\t\t\n\t\t\t\tif (color.a == 0.0 && (colorU.a != 0.0 || colorD.a != 0.0 || colorL.a != 0.0 || colorR.a != 0.0) ) {\n\t\t\t\t\tgl_FragColor = vec4(1.0, 1.0, 1.0, .2);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (color.a == 0.0) discard;\n\t\t\t\t\tcolor += vec4(0.1, 0.1, 0.1, 0);\n\t\t\t\t\tgl_FragColor = color;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}" }; _this = _super.call(this, config) || this; return _this; } return OutlinePipeline; }(Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline)); +var TextInput = /** @class */ (function (_super) { + __extends(TextInput, _super); + function TextInput(scene, x, y) { + var _this = _super.call(this, scene, x, y, " ", "ui_text_input") || this; + _this.text = ""; + document.addEventListener("keydown", function (e) { + var code = e.keyCode; + if (code == 8) { + _this.text = _this.text.substr(0, _this.text.length - 1); + _this.setText(_this.text); + return; + } + else if (code == 13) { + //Send + return; + } + else if (e.key.length != 1) + return; + _this.text += e.key; + _this.setText(_this.text.length == 0 ? " " : _this.text); + }); + return _this; + } + return TextInput; +}(ChatBox)); var TileMap = /** @class */ (function () { function TileMap(key, scene, xwid, ywid) { this.SOLID = 10; @@ -379,90 +304,95 @@ var TileMap = /** @class */ (function () { this.scene = scene; this.dimensions = { x: xwid, y: ywid }; this.solid_at = []; + this.palette_at = []; for (var i = 0; i < xwid; i++) { this.solid_at[i] = []; + this.palette_at[i] = []; for (var j = 0; j < ywid; j++) { - this.solid_at[i][j] = -1; + this.solid_at[i][j] = false; + this.palette_at[i][j] = 1; } } this.map = this.scene.add.tilemap(null, 16, 16, 0, 0); - for (var i = 1; i < this.scene.TILESET_COUNT; i++) { - var tileset = this.map.addTilesetImage("tileset_" + i, "tileset " + i, 16, 16, 0, 0); - this.map.setLayer("layer_" + i); - this.layers[i - 1] = this.map.createBlankDynamicLayer("layer_" + i, "tileset_" + i, 0, 0, 50 * 16, 50 * 16, 16, 16); - this.layers[i - 1].setScale(4, 4); + for (var i = 0; i < this.scene.TILESET_COUNT; i++) { + var tileset = this.map.addTilesetImage("tileset_" + i, "tileset_" + i, 16, 16, 0, 0); + this.layers[i] = null; } + this.createLayer(0); this.layers[0].setInteractive(); this.map.addTilesetImage("grid_tile", "grid_tile", 16, 16, 0, 0); this.map.setLayer("grid"); var gridlayer = this.map.createBlankDynamicLayer("grid", "grid_tile", 0, 0, 50 * 16, 50 * 16, 16, 16); gridlayer.setScale(4, 4); + gridlayer.setDepth(500); for (var i = 0; i < xwid; i++) { for (var j = 0; j < ywid; j++) { if ((j % 2 == 0 && i % 2 == 0) || (j % 2 != 0 && i % 2 != 0)) gridlayer.putTileAt(0, i, j); } } - } - TileMap.prototype.fillMap = function (pid) { - if (!pid) - pid = 1; for (var x = 0; x < this.dimensions.x; x++) { for (var y = 0; y < this.dimensions.y; y++) { - this.setTile(x, y, pid, 13); + this.setTile(x, y, 1, 13); } } + } + TileMap.prototype.createLayer = function (palette) { + this.map.setLayer("layer_" + palette); + this.layers[palette] = this.map.createBlankDynamicLayer("layer_" + palette, "tileset_" + palette, 0, 0, 50 * 16, 50 * 16, 16, 16); + this.layers[palette].setScale(4, 4); + this.layers[palette].setDepth(-500 + palette); }; TileMap.prototype.setSolid = function (x, y, palette, solid) { - var alreadySolid = this.getSolid(x, y); - if (alreadySolid == solid) + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) return false; - if (solid) - this.setTile(x, y, 0, this.SOLID); - else - this.setTile(x, y, 0, 13); + var oldPalette = this.palette_at[x][y]; + var wasSolid = this.solid_at[x][y]; + if (wasSolid == solid && palette == oldPalette) + return false; + this.setTile(x, y, palette, (solid ? this.SOLID : 13)); this.calculateEdgesAround(x, y); return true; }; TileMap.prototype.getSolid = function (x, y) { - return this.getTile(x, y, 0) == this.SOLID; + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) + return -1; + return (this.solid_at[x][y]) ? this.palette_at[x][y] : -1; + }; + TileMap.prototype.getPalette = function (x, y) { + if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) + return -1; + return this.palette_at[x][y]; }; TileMap.prototype.setTile = function (x, y, palette, tid) { - this.layers[0].removeTileAt(x, y, true); - this.layers[0].putTileAt(tid, x, y); - }; - TileMap.prototype.getTile = function (x, y, palette) { - if (x < 0 || y < 0 || x > this.dimensions.x - 1 || y > this.dimensions.y - 1) - return this.SOLID; - return this.layers[0].getTileAt(x, y, true).index; + if (this.layers[palette] == null) + this.createLayer(palette); + this.layers[this.palette_at[x][y]].removeTileAt(x, y, true); + this.layers[palette].putTileAt(tid, x, y); + this.palette_at[x][y] = palette; + this.solid_at[x][y] = tid == this.SOLID; }; TileMap.prototype.calculateEdgesAround = function (x, y) { - for (var i = clamp(x - 1, this.dimensions.x - 1, 0); i <= clamp(x + 1, this.dimensions.x + 1, 0); i++) { - for (var j = clamp(y - 1, this.dimensions.y - 1, 0); j <= clamp(y + 1, this.dimensions.y + 1, 0); j++) { - this.calculateEdges(i, j); + for (var i = clamp(x - 1, this.dimensions.x - 1, 0); i <= clamp(x + 1, this.dimensions.x - 1, 0); i++) { + for (var j = clamp(y - 1, this.dimensions.y - 1, 0); j <= clamp(y + 1, this.dimensions.y - 1, 0); j++) { + var tile = this.calculateEdges(i, j); + if (tile != -1) + this.setTile(i, j, this.palette_at[i][j], tile); } } }; - TileMap.prototype.getSurroundingTiles = function (x, y) { - var tiles = []; - for (var i = -1; i <= 1; i++) { - for (var j = -1; j <= 1; j++) { - //TODO: Make this palette independant - tiles.push(this.getTile(x + j, y + i, 0)); - } - } - return tiles; - }; TileMap.prototype.getSurroundingSolid = function (x, y) { - var tiles = this.getSurroundingTiles(x, y); - for (var i = 0; i < 9; i++) { - tiles[i] = (tiles[i] == this.SOLID); + var solid = []; + for (var i = -1; i <= 1; i++) { + for (var j = -1; j <= 1; j++) { + solid.push(this.getSolid(x + j, y + i) != -1); + } } - return tiles; + return solid; }; TileMap.prototype.calculateEdges = function (x, y) { - if (this.getTile(x, y, 0) == this.SOLID) - return; + if (this.getSolid(x, y) != -1) + return -1; var adjacents = this.getSurroundingSolid(x, y); var tile = 13; if (adjacents[7] /*Bottom*/) { @@ -599,34 +529,74 @@ var TileMap = /** @class */ (function () { } else if (adjacents[8] /*Bottom right*/) tile = 0; - this.setTile(x, y, 0, tile); + return tile; }; return TileMap; }()); +var TilesetPatcher = /** @class */ (function () { + function TilesetPatcher(scene) { + var renderTex = new Phaser.GameObjects.RenderTexture(scene, 0, 0, 9 * 16, 7 * 16 * 8); + renderTex.drawFrame("tileset_0", 0, 0, 7 * 16 * 0); + renderTex.drawFrame("tileset_1", 0, 0, 7 * 16 * 1); + renderTex.drawFrame("tileset_2", 0, 0, 7 * 16 * 2); + scene.add.existing(renderTex); + // scene.textures.addRenderTexture("tileset_16x", renderTex); + // let spr = scene.add.sprite(300, 300, "tileset_16x"); + // console.log(spr); + } + return TilesetPatcher; +}()); var Token = /** @class */ (function (_super) { __extends(Token, _super); function Token(scene, x, y, tex) { var _this = _super.call(this, scene, x, y) || this; - _this.shadow = new Phaser.GameObjects.Sprite(scene, -4, -4, tex); - _this.shadow.setOrigin(0, 0); - _this.shadow.setScale(4, 1); - _this.shadow.setTint(0x000000); - _this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3); - _this.list.push(_this.shadow); - _this.width = _this.shadow.width * 4; - _this.height = _this.shadow.height * 4; - _this.shadow.y = _this.height - 24; - _this.sprite = new Phaser.GameObjects.Sprite(scene, -4, -4, tex); - _this.sprite.setOrigin(0, 0); - _this.sprite.setScale(4, 4); - _this.setPosition(x, y); - _this.list.push(_this.sprite); - _this.scene.add.existing(_this); + _this.sprite = null; + _this.shadow = null; + _this.currentFrame = 0; + _this.setTexture(tex); + _this.uuid = generateId(32); return _this; } + Token.prototype.setTexture = function (tex) { + if (this.shadow != null) + this.shadow.setTexture(tex); + else { + this.shadow = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex); + this.shadow.setOrigin(0, 0); + this.shadow.setScale(4, 1); + this.shadow.setTint(0x000000); + this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3); + this.list.push(this.shadow); + } + this.width = this.shadow.width * 4; + this.height = this.shadow.height * 4; + this.shadow.y = this.height - 24; + if (this.sprite != null) + this.sprite.setTexture(tex); + else { + this.sprite = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex); + this.sprite.setOrigin(0, 0); + this.sprite.setScale(4, 4); + this.setPosition(this.x / 4, this.y / 4); + this.list.push(this.sprite); + } + }; + Token.prototype.setFrame = function (frame) { + this.currentFrame = frame; + this.sprite.setFrame(frame); + this.shadow.setFrame(frame); + }; + Token.prototype.getFrame = function () { + return this.currentFrame; + }; + Token.prototype.frameCount = function () { + return Object.keys(this.sprite.texture.frames).length - 1; + }; Token.prototype.toggleOutline = function (outline) { - if (outline) + if (outline) { this.sprite.setPipeline("outline"); + this.sprite.pipeline.setFloat1("tex_size", this.sprite.texture.source[0].width); + } else this.sprite.resetPipeline(); }; @@ -637,16 +607,54 @@ var Token = /** @class */ (function (_super) { Token.prototype.getPosition = function () { return new Vec2(this.x / 4, this.y / 4); }; + // For converting token to / from serialized data + Token.prototype.serialize = function () { + return JSON.stringify({ + uuid: this.uuid, + sprite: this.sprite.texture.key, + frame: this.currentFrame, + x: this.x / 4, + y: this.y / 4 + }); + }; + Token.deserialize = function (scene, serialized) { + var tkn = new Token(scene, 0, 0, ""); + tkn.loadSerializedData(serialized); + return tkn; + }; + Token.prototype.loadSerializedData = function (serialized) { + var tbl = JSON.parse(serialized); + this.uuid = tbl.uuid; + this.setTexture(tbl.sprite); + this.setFrame(tbl.frame); + this.setPosition(tbl.x, tbl.y); + }; return Token; }(Phaser.GameObjects.Container)); var UIView = /** @class */ (function () { function UIView(scene) { + this.visibleMenu = 0; this.uiActive = false; this.scene = scene; this.camera = this.scene.cameras.add(0, 0, this.scene.cameras.main.width, this.scene.cameras.main.height, false, "ui_camera"); this.camera.scrollX = -10000; this.o = this.scene.add.container(-10000, 0); } + UIView.prototype.createElements = function () { + this.o.add(new UIModeSwitchButton(this.scene, 14 + 10, 1)); + this.o.add(new UIHistoryManipulation(this.scene, 14 + 25, 1)); + this.tokenSidebar = new UITokenSidebar(this.scene, -205, 0); + this.o.add(this.tokenSidebar); + for (var _i = 0, TOKENS_1 = TOKENS; _i < TOKENS_1.length; _i++) { + var t = TOKENS_1[_i]; + this.tokenSidebar.addToken(t.key); + } + this.tileSidebar = new UITileSidebar(this.scene, 0, 0); + this.o.add(this.tileSidebar); + this.tileSidebar.addPalette(0); + this.tileSidebar.addPalette(1); + this.tileSidebar.addPalette(2); + }; UIView.prototype.update = function () { this.uiActive = false; for (var _i = 0, _a = this.o.list; _i < _a.length; _i++) { @@ -655,6 +663,55 @@ var UIView = /** @class */ (function () { if (!this.uiActive && o.mouseIntersects()) this.uiActive = true; } + if (this.visibleMenu != this.scene.mode) { + this.visibleMenu = this.scene.mode; + if (this.scene.mode == 0) { + this.displayArchitect(); + this.hideToken(); + } + else { + this.hideArchitect(); + this.displayToken(); + } + } + }; + UIView.prototype.displayArchitect = function () { + this.o.bringToTop(this.tileSidebar); + this.scene.tweens.add({ + targets: this.tileSidebar, + x: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + }; + UIView.prototype.hideToken = function () { + this.scene.tweens.add({ + targets: this.tokenSidebar, + x: -205, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + }; + UIView.prototype.displayToken = function () { + this.o.bringToTop(this.tokenSidebar); + this.scene.tweens.add({ + targets: this.tokenSidebar, + x: 0, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); + }; + UIView.prototype.hideArchitect = function () { + this.scene.tweens.add({ + targets: this.tileSidebar, + x: -205, + ease: 'Cubic', + duration: 300, + repeat: 0 + }); }; return UIView; }()); @@ -666,6 +723,17 @@ function clamp(x, min, max) { } return Math.max(Math.min(x, max), min); } +function dec2hex(dec) { + return ('0' + dec.toString(16)).substr(-2); +} +function generateId(len) { + var arr = new Uint8Array((len || 40) / 2); + window.crypto.getRandomValues(arr); + var stringArr = []; + for (var i = 0; i < arr.length; i++) + stringArr.push(dec2hex(arr[i])); + return stringArr.join(''); +} var Vec2 = /** @class */ (function () { function Vec2(x, y) { this.x = 0; @@ -733,9 +801,11 @@ var WorldView = /** @class */ (function () { this.scene.events.on('destroy', function () { return document.documentElement.removeEventListener("wheel", _this.onWheel); }); }; WorldView.prototype.onWheel = function (e) { - var dir = (e.deltaY < 0 ? 1 : -1); - this.zoomLevel = clamp(this.zoomLevel + dir, 0, this.zoomLevels.length - 1); - this.camera.setZoom(this.zoomLevels[this.zoomLevel] / 100); + if (!(this.scene.mode == 1 && this.scene.token.currentToken != null)) { + var dir = (e.deltaY < 0 ? 1 : -1); + this.zoomLevel = clamp(this.zoomLevel + dir, 0, this.zoomLevels.length - 1); + this.camera.setZoom(this.zoomLevels[this.zoomLevel] / 100); + } }; WorldView.prototype.pan = function () { if (this.scene.input.mousePointer.middleButtonDown()) { @@ -752,10 +822,52 @@ var WorldView = /** @class */ (function () { }; return WorldView; }()); +var TOKENS = [ + { name: "Armor 1", key: "tkn_armor_1", file: "res/token/armor_1", split_by: 18 }, + { name: "Cadin 1", key: "tkn_cadin_1", file: "res/token/cadin_1", split_by: 18 }, + { name: "Cadin 2", key: "tkn_cadin_2", file: "res/token/cadin_2", split_by: 18 }, + { name: "Cadin 3", key: "tkn_cadin_3", file: "res/token/cadin_3", split_by: 18 }, + { name: "Cleric F", key: "tkn_cleric_f", file: "res/token/cleric_female", split_by: 18 }, + { name: "Cleric M", key: "tkn_cleric_m", file: "res/token/cleric_male", split_by: 18 }, + { name: "Dragonfolk 1", key: "tkn_dragonfolk_1", file: "res/token/dragonfolk_1", split_by: 18 }, + { name: "Dragonfolk 2", key: "tkn_dragonfolk_2", file: "res/token/dragonfolk_2", split_by: 18 }, + { name: "Dragonfolk 3", key: "tkn_dragonfolk_3", file: "res/token/dragonfolk_3", split_by: 18 }, + { name: "Tori 1", key: "tkn_tori_1", file: "res/token/tori_1", split_by: 18 }, + { name: "Tori 2", key: "tkn_tori_2", file: "res/token/tori_2", split_by: 18 }, + { name: "Tori 3", key: "tkn_tori_3", file: "res/token/tori_3", split_by: 18 }, + { name: "Tori 4", key: "tkn_tori_4", file: "res/token/tori_4", split_by: 18 }, + { name: "Dragonfolk Knight 1", key: "tkn_dragonknight_1", file: "res/token/dragonfolk_knight_1", split_by: 18 }, + { name: "Dragonfolk Knight 2", key: "tkn_dragonknight_2", file: "res/token/dragonfolk_knight_2", split_by: 18 }, + { name: "Dragonfolk Knight 3", key: "tkn_dragonknight_3", file: "res/token/dragonfolk_knight_3", split_by: 18 }, + { name: "Druid M", key: "tkn_druid_m", file: "res/token/druid_male", split_by: 18 }, + { name: "Feline 1", key: "tkn_feline_1", file: "res/token/feline_1", split_by: 18 }, + { name: "Knight 1", key: "tkn_knight_1", file: "res/token/knight_1", split_by: 18 }, + { name: "Robot 1", key: "tkn_robot_1", file: "res/token/robot_1", split_by: 18 }, + { name: "Rockfriend Green", key: "tkn_rockfriend_g", file: "res/token/rockfriend_1", split_by: 18 }, + { name: "Rockfriend Blue", key: "tkn_rockfriend_b", file: "res/token/rockfriend_2", split_by: 18 }, + { name: "Rockfriend Red", key: "tkn_rockfriend_r", file: "res/token/rockfriend_3", split_by: 18 }, + { name: "Rockfriend Teal", key: "tkn_rockfriend_t", file: "res/token/rockfriend_4", split_by: 18 }, + { name: "Wizard F", key: "tkn_wizard_f", file: "res/token/wizard_female", split_by: 18 }, + { name: "Wizard M", key: "tkn_wizard_m", file: "res/token/wizard_male", split_by: 18 }, + { name: "Cloaked Person", key: "tkn_cloaked_person", file: "res/token/cloaked_person", split_by: 18 }, + { name: "Dwarf M 1", key: "tkn_dwarf_m_1", file: "res/token/dwarf_m_1", split_by: 18 }, + { name: "Dwarf M 2", key: "tkn_dwarf_m_2", file: "res/token/dwarf_m_2", split_by: 18 }, + { name: "Skeleton", key: "tkn_skeleton", file: "res/token/skeleton", split_by: 18 }, + { name: "Naexi", key: "tkn_naexi", file: "res/token/naexi_human_noweapon", split_by: 18 }, + { name: "Naexi w/ Yklwa", key: "tkn_naexi_yklwa", file: "res/token/naexi_human_yklwa", split_by: 18 }, + { name: "Naexi Anthro Form", key: "tkn_naexi_anthro", file: "res/token/naexi_anthro", split_by: 18 }, + { name: "bones", key: "tkn_bones", file: "res/token/bones" }, + { name: "treasure", key: "tkn_treasure", file: "res/token/treasure" }, +]; var ArchitectMode = /** @class */ (function () { function ArchitectMode(scene) { + var _this = this; this.active = false; + this.primitives = []; + this.startTilePos = new Vec2(); + this.placeMode = "brush"; this.pointerDown = false; + this.pointerPrimaryDown = false; this.manipulated = []; this.scene = scene; // Create cursor hover sprite @@ -763,6 +875,14 @@ var ArchitectMode = /** @class */ (function () { this.cursor.setScale(4, 4); this.cursor.setDepth(1000); this.cursor.setOrigin(0, 0); + this.scene.snapKey.addListener("down", function () { if (!_this.scene.input.activePointer.isDown) + _this.placeMode = "line"; }); + this.scene.modifierKey.addListener("down", function () { if (!_this.scene.input.activePointer.isDown) + _this.placeMode = "rect"; }); + this.scene.snapKey.addListener("up", function () { if (!_this.scene.input.activePointer.isDown) + _this.placeMode = "brush"; }); + this.scene.modifierKey.addListener("up", function () { if (!_this.scene.input.activePointer.isDown) + _this.placeMode = "brush"; }); } ArchitectMode.prototype.update = function () { this.active = true; @@ -771,15 +891,114 @@ var ArchitectMode = /** @class */ (function () { this.cursor.setPosition(selectedTilePos.x * 64, selectedTilePos.y * 64); this.cursor.setVisible((selectedTilePos.x >= 0 && selectedTilePos.y >= 0 && selectedTilePos.x < this.scene.map.dimensions.x && selectedTilePos.y < this.scene.map.dimensions.y)); - if (this.scene.input.activePointer.isDown && !this.pointerDown) + // Place Tiles + switch (this.placeMode) { + case "brush": { + this.drawBrush(selectedTilePos); + break; + } + case "line": { + this.drawLine(selectedTilePos); + break; + } + case "rect": { + this.drawRect(selectedTilePos); + break; + } + } + // Push history to HistoryManager + if (this.scene.input.activePointer.isDown && !this.pointerDown) { this.pointerDown = true; + this.pointerPrimaryDown = this.scene.input.activePointer.leftButtonDown(); + } else if (!this.scene.input.activePointer.isDown && this.pointerDown) { if (this.manipulated.length != 0) { this.scene.history.push("tile", this.manipulated); this.manipulated = []; } this.pointerDown = false; + this.pointerPrimaryDown = false; } + }; + ArchitectMode.prototype.drawLine = function (selectedTilePos) { + if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { + if (!this.pointerDown) + this.startTilePos = selectedTilePos; + var a = new Vec2(this.startTilePos.x, this.startTilePos.y); + var b = new Vec2(selectedTilePos.x, selectedTilePos.y); + if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) + b.y = a.y; + else + b.x = a.x; + this.cursor.setPosition(b.x * 64, b.y * 64); + this.primitives.forEach(function (v) { return v.destroy(); }); + this.primitives = []; + this.primitives.push(this.scene.add.line(0, 0, a.x + 0.5, a.y + 0.5, b.x + 0.5, b.y + 0.5, 0xffffff, 1)); + this.primitives.forEach(function (v) { + v.setOrigin(0, 0); + v.setScale(64, 64); + v.setLineWidth(0.03); + v.setDepth(300); + }); + this.primitives.push(this.scene.add.sprite(this.startTilePos.x * 64, this.startTilePos.y * 64, "cursor")); + this.primitives[1].setOrigin(0, 0); + this.primitives[1].setScale(4, 4); + this.primitives[1].setAlpha(0.5); + } + else if (!this.scene.input.mousePointer.leftButtonDown() && !this.scene.input.mousePointer.rightButtonDown() && this.pointerDown) { + var a = new Vec2(this.startTilePos.x * 64, this.startTilePos.y * 64); + var b = new Vec2(selectedTilePos.x * 64, selectedTilePos.y * 64); + if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) + b.y = a.y; + else + b.x = a.x; + var change = new Vec2(b.x - a.x, b.y - a.y); + var normalizeFactor = Math.sqrt(change.x * change.x + change.y * change.y); + change.x /= normalizeFactor; + change.y /= normalizeFactor; + while (Math.abs(b.x - a.x) >= 1 || Math.abs(b.y - a.y) >= 1) { + this.placeTileAndPushManip(new Vec2(Math.floor(a.x / 64), Math.floor(a.y / 64)), this.pointerPrimaryDown); + a.x += change.x; + a.y += change.y; + } + this.placeTileAndPushManip(new Vec2(b.x / 64, b.y / 64), this.pointerPrimaryDown); + this.primitives.forEach(function (v) { return v.destroy(); }); + this.primitives = []; + } + }; + ArchitectMode.prototype.drawRect = function (selectedTilePos) { + if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { + if (!this.pointerDown) + this.startTilePos = selectedTilePos; + var a = new Vec2(Math.min(this.startTilePos.x, selectedTilePos.x), Math.min(this.startTilePos.y, selectedTilePos.y)); + var b = new Vec2(Math.max(this.startTilePos.x, selectedTilePos.x), Math.max(this.startTilePos.y, selectedTilePos.y)); + this.primitives.forEach(function (v) { return v.destroy(); }); + this.primitives = []; + var fac = 0.03; + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, a.y + fac, b.x + 1 - fac, a.y + fac, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, a.y + fac / 2, a.x + fac, b.y + 1 - fac / 2, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, a.x + fac, b.y + 1 - fac, b.x + 1 - fac, b.y + 1 - fac, 0xffffff, 1)); + this.primitives.push(this.scene.add.line(0, 0, b.x + 1 - fac, a.y + fac / 2, b.x + 1 - fac, b.y + 1 - fac / 2, 0xffffff, 1)); + this.primitives.forEach(function (v) { + v.setOrigin(0, 0); + v.setScale(64, 64); + v.setLineWidth(0.03); + v.setDepth(300); + }); + } + else if (!this.scene.input.mousePointer.leftButtonDown() && !this.scene.input.mousePointer.rightButtonDown() && this.pointerDown) { + var a = new Vec2(Math.min(this.startTilePos.x, selectedTilePos.x), Math.min(this.startTilePos.y, selectedTilePos.y)); + var b = new Vec2(Math.max(this.startTilePos.x, selectedTilePos.x), Math.max(this.startTilePos.y, selectedTilePos.y)); + for (var i = a.x; i <= b.x; i++) { + for (var j = a.y; j <= b.y; j++) { + this.placeTileAndPushManip(new Vec2(i, j), this.pointerPrimaryDown); + } + } + this.primitives.forEach(function (v) { return v.destroy(); }); + this.primitives = []; + } + }; + ArchitectMode.prototype.drawBrush = function (selectedTilePos) { if (this.scene.input.mousePointer.leftButtonDown() || this.scene.input.mousePointer.rightButtonDown()) { var change = new Vec2(this.scene.world.cursorWorld.x - this.scene.world.lastCursorWorld.x, this.scene.world.cursorWorld.y - this.scene.world.lastCursorWorld.y); var normalizeFactor = Math.sqrt(change.x * change.x + change.y * change.y); @@ -787,17 +1006,27 @@ var ArchitectMode = /** @class */ (function () { change.y /= normalizeFactor; var place = new Vec2(this.scene.world.lastCursorWorld.x, this.scene.world.lastCursorWorld.y); while (Math.abs(this.scene.world.cursorWorld.x - place.x) >= 1 || Math.abs(this.scene.world.cursorWorld.y - place.y) >= 1) { - if (this.scene.map.setSolid(Math.floor(place.x / 64), Math.floor(place.y / 64), this.scene.input.mousePointer.rightButtonDown())) { - this.manipulated.push({ pos: new Vec2(Math.floor(place.x / 64), Math.floor(place.y / 64)), solid: this.scene.input.mousePointer.rightButtonDown() }); - } + this.placeTileAndPushManip(new Vec2(Math.floor(place.x / 64), Math.floor(place.y / 64)), this.scene.input.mousePointer.leftButtonDown()); place.x += change.x; place.y += change.y; } - if (this.scene.map.setSolid(selectedTilePos.x, selectedTilePos.y, this.scene.input.mousePointer.rightButtonDown())) { - this.manipulated.push({ pos: selectedTilePos, solid: this.scene.input.mousePointer.rightButtonDown() }); - } + this.placeTileAndPushManip(new Vec2(selectedTilePos.x, selectedTilePos.y), this.scene.input.mousePointer.leftButtonDown()); } }; + ArchitectMode.prototype.placeTileAndPushManip = function (manipPos, solid) { + var wasSolid = this.scene.map.getSolid(manipPos.x, manipPos.y) != -1; + var lastPalette = this.scene.map.getPalette(manipPos.x, manipPos.y); + var changed = this.scene.map.setSolid(manipPos.x, manipPos.y, this.scene.activePalette, solid); + if (!changed) + return; + this.manipulated.push({ + pos: manipPos, + solid: solid, + oldSolid: wasSolid, + palette: this.scene.activePalette, + oldPalette: lastPalette + }); + }; ArchitectMode.prototype.cleanup = function () { if (!this.active) return; @@ -808,36 +1037,62 @@ var ArchitectMode = /** @class */ (function () { }()); var TokenMode = /** @class */ (function () { function TokenMode(scene) { + var _this = this; this.active = false; this.currentToken = null; this.pointerDown = false; + this.currentSerialized = ""; this.scene = scene; + this.onWheel = this.onWheel.bind(this); + document.documentElement.addEventListener("wheel", this.onWheel); + this.scene.events.on('destroy', function () { return document.documentElement.removeEventListener("wheel", _this.onWheel); }); } + TokenMode.prototype.onWheel = function (e) { + if (this.currentToken != null) { + var dir = e.deltaY > 0 ? 1 : -1; + var frame = this.currentToken.getFrame() + dir; + if (frame < 0) + frame += this.currentToken.frameCount(); + frame %= this.currentToken.frameCount(); + this.currentToken.setFrame(frame); + } + }; TokenMode.prototype.update = function () { this.active = true; - for (var _i = 0, _a = this.scene.tokens; _i < _a.length; _i++) { - var token = _a[_i]; - if (this.scene.world.cursorWorld.x >= token.x && this.scene.world.cursorWorld.y >= token.y + var foundToHighlight = false; + for (var i = this.scene.tokens.length - 1; i >= 0; i--) { + var token = this.scene.tokens[i]; + if (!foundToHighlight && this.scene.world.cursorWorld.x >= token.x && this.scene.world.cursorWorld.y >= token.y && this.scene.world.cursorWorld.x <= token.x + token.width && this.scene.world.cursorWorld.y <= token.y + token.height) { token.toggleOutline(true); + foundToHighlight = true; if (this.scene.input.mousePointer.leftButtonDown() && !this.pointerDown && this.currentToken == null) { this.grabOffset = new Vec2(this.scene.world.cursorWorld.x - token.x, this.scene.world.cursorWorld.y - token.y); this.startPosition = token.getPosition(); this.currentToken = token; + this.currentSerialized = this.currentToken.serialize(); this.pointerDown = true; } } - else + else if (this.currentToken != token) token.toggleOutline(false); } + if (this.currentToken == null && this.scene.input.mousePointer.leftButtonDown()) { + var token = new Token(this.scene, Math.floor(this.scene.world.cursorWorld.x / 4 / 16) * 16, Math.floor(this.scene.world.cursorWorld.y / 4 / 16) * 16, this.scene.activeToken); + this.scene.add.existing(token); + this.scene.tokens.push(token); + this.scene.history.push("token_create", { data: token.serialize() }); + } if (!this.scene.input.mousePointer.leftButtonDown() && this.pointerDown && this.currentToken != null) { - for (var _b = 0, _c = this.scene.tokens; _b < _c.length; _b++) { - var token = _c[_b]; - token.toggleOutline(false); + for (var _i = 0, _a = this.scene.tokens; _i < _a.length; _i++) { + var token = _a[_i]; + if (token != this.currentToken) + token.toggleOutline(false); } - if (this.currentToken.getPosition().x != this.startPosition.x || this.currentToken.getPosition().y != this.startPosition.y) - this.scene.history.push("token_move", { start: this.startPosition, end: this.currentToken.getPosition(), token: this.currentToken }); + if (JSON.stringify(this.currentToken.serialize()) != JSON.stringify(this.currentSerialized)) + this.scene.history.push("token_modify", { old: this.currentSerialized, new: this.currentToken.serialize() }); this.currentToken = null; + this.currentSerialized = ""; this.pointerDown = false; } if (this.currentToken != null) { @@ -861,6 +1116,173 @@ var TokenMode = /** @class */ (function () { }; return TokenMode; }()); +var GetAssetsScene = /** @class */ (function (_super) { + __extends(GetAssetsScene, _super); + function GetAssetsScene() { + return _super.call(this, { key: "GetAssetsScene" }) || this; + } + GetAssetsScene.prototype.preload = function () { + this.cameras.main.setBackgroundColor("#6a655a"); + this.load.image('splash', '/res/splash.png'); + this.load.text("assets", "res/_assets.txt"); + }; + GetAssetsScene.prototype.create = function () { + var assets = this.cache.text.get("assets"); + var lines = assets.split("\n"); + var assetsParsed = ""; + var prefixes = {}; + lines.forEach(function (v) { + if (v.substr(0, "FOLDERPREFIX".length) == "FOLDERPREFIX") { + var tokens = v.split(" "); + prefixes[tokens[1]] = tokens[2]; + return; + } + if (v.length == 0) + return; + var slash = v.indexOf('/'); + var prefix = ""; + if (slash != -1 && prefixes[v.substr(0, slash)] != undefined) + prefix = prefixes[v.substr(0, slash)]; + if (slash == -1) + assetsParsed += v.split(" ")[0] + " " + v + "\n"; + else + assetsParsed += "" + prefix + v.substring(slash + 1, v.length).split(" ")[0] + " " + v + "\n"; + }); + this.cache.text.remove("assets"); + this.cache.text.add("assets", assetsParsed); + this.game.scene.start('LoadScene'); + this.game.scene.stop('GetAssetsScene'); + this.game.scene.swapPosition('LoadScene', 'GetAssetsScene'); + }; + return GetAssetsScene; +}(Phaser.Scene)); +var LoadScene = /** @class */ (function (_super) { + __extends(LoadScene, _super); + function LoadScene() { + return _super.call(this, { key: "LoadScene" }) || this; + } + LoadScene.prototype.preload = function () { + this.cameras.main.setBackgroundColor("#6a655a"); + this.add.sprite(this.cameras.main.width / 2, this.cameras.main.height / 2, "splash"); + this.load.bitmapFont('font1x', '/res/font/font1.png', '/res/font/font1.fnt'); + this.load.bitmapFont('font2x', '/res/font/font2.png', '/res/font/font2.fnt'); + this.load.bitmapFont('font3x', '/res/font/font3.png', '/res/font/font3.fnt'); + for (var _i = 0, _a = this.cache.text.get("assets").split("\n"); _i < _a.length; _i++) { + var s = _a[_i]; + var tokens = s.split(" "); + if (tokens.length == 2) + this.load.image(tokens[0], "/res/" + tokens[1] + ".png"); + else if (tokens.length == 4) + this.load.spritesheet(tokens[0], "/res/" + tokens[1] + ".png", { frameWidth: parseInt(tokens[2]), frameHeight: parseInt(tokens[3]) }); + } + for (var _b = 0, TOKENS_2 = TOKENS; _b < TOKENS_2.length; _b++) { + var t = TOKENS_2[_b]; + if (t.split_by != undefined) + this.load.spritesheet(t.key, t.file + ".png", { frameWidth: t.split_by, frameHeight: t.split_by }); + else + this.load.image(t.key, t.file + ".png"); + } + }; + LoadScene.prototype.create = function () { + var _this = this; + this.cache.text.remove("assets"); + setTimeout(function () { + _this.game.scene.start('MainScene'); + _this.game.scene.stop('LoadScene'); + _this.game.scene.swapPosition('MainScene', 'LoadScene'); + }, 50); + }; + return LoadScene; +}(Phaser.Scene)); +var MainScene = /** @class */ (function (_super) { + __extends(MainScene, _super); + function MainScene() { + var _this = _super.call(this, { key: "MainScene" }) || this; + _this.TILESET_COUNT = 3; + _this.mode = 0; + _this.tokens = []; + _this.timeHoldingHistoryKey = 0; + _this.activePalette = 0; + _this.activeToken = "tkn_treasure"; + return _this; + } + MainScene.prototype.preload = function () { + var _this = this; + window.addEventListener('resize', function () { + var frame = document.getElementById("game"); + _this.game.scale.resize(frame.offsetWidth, frame.offsetHeight); + _this.chat.x = -10000 + _this.cameras.main.width - 309; + }); + }; + MainScene.prototype.create = function () { + var _this = this; + this.snapKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); + this.modifierKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.CTRL); + this.switchModeKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.TAB); + this.undoRedoKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z); + this.redoKeyWin = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Y); + this.switchModeKey.addListener("down", function () { _this.mode = _this.mode == 0 ? 1 : 0; }); + this.undoRedoKey.addListener("down", function () { + if (!_this.modifierKey.isDown) + return; + _this.timeHoldingHistoryKey = 0; + _this.snapKey.isDown ? _this.history.redo() : _this.history.undo(); + }); + this.redoKeyWin.addListener("down", function () { + _this.timeHoldingHistoryKey = 0; + if (!_this.modifierKey.isDown) + return; + _this.history.redo(); + }); + this.game.renderer.addPipeline('outline', new OutlinePipeline(this.game)); + this.history = new HistoryManager(this); + this.world = new WorldView(this); + this.ui = new UIView(this); + this.ui.createElements(); + this.chat = new Chat(this, -10000 + this.cameras.main.width - 309, this.cameras.main.height - 9); + this.add.existing(this.chat); + this.map = new TileMap("gameMap", this, 300, 300); + this.architect = new ArchitectMode(this); + this.token = new TokenMode(this); + var tileset = new TilesetPatcher(this); + }; + MainScene.prototype.update = function (time, delta) { + this.world.update(); + this.ui.update(); + this.chat.update(); + if ((this.redoKeyWin.isDown || this.undoRedoKey.isDown) && this.modifierKey.isDown) { + if (this.timeHoldingHistoryKey > 12 && this.timeHoldingHistoryKey % 3 == 0) { + if (this.redoKeyWin.isDown) + this.history.redo(); + else if (this.snapKey.isDown) + this.history.redo(); + else + this.history.undo(); + } + this.timeHoldingHistoryKey++; + } + else { + this.timeHoldingHistoryKey = 0; + } + if (this.mode == 0) { + if (this.ui.uiActive) + this.architect.cleanup(); + else { + this.architect.update(); + this.token.cleanup(); + } + } + else { + if (this.ui.uiActive) + this.token.cleanup(); + else { + this.token.update(); + this.architect.cleanup(); + } + } + }; + return MainScene; +}(Phaser.Scene)); var UIComponent = /** @class */ (function (_super) { __extends(UIComponent, _super); function UIComponent(scene, x, y, tex) { @@ -868,6 +1290,7 @@ var UIComponent = /** @class */ (function (_super) { _this.setOrigin(0, 0); _this.setScale(3, 3); _this.setPos(x * 3, y * 3); + _this.setActive(true); _this.scene.add.existing(_this); return _this; } @@ -884,6 +1307,41 @@ var UIComponent = /** @class */ (function (_super) { }; return UIComponent; }(Phaser.GameObjects.Sprite)); +var UIContainer = /** @class */ (function (_super) { + __extends(UIContainer, _super); + function UIContainer(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.intersects = []; + _this.setPos(x * 3, y * 3); + _this.setActive(true); + _this.scene.add.existing(_this); + return _this; + } + UIContainer.prototype.setPos = function (x, y) { + this.setPosition(x * 3, y * 3); + }; + UIContainer.prototype.mouseIntersects = function () { + for (var _i = 0, _a = this.list; _i < _a.length; _i++) { + var i = _a[_i]; + if (i.mouseIntersects != null) + if (i.mouseIntersects()) + return true; + } + for (var _b = 0, _c = this.intersects; _b < _c.length; _b++) { + var i = _c[_b]; + var pointer = this.scene.input.mousePointer; + if (pointer.x >= this.x + i.x && pointer.y >= this.y + i.y + && pointer.x <= this.x + i.x + i.width * i.scaleX && pointer.y <= this.y + i.y + i.height * i.scaleY) + return true; + } + return false; + }; + UIContainer.prototype.mousePos = function () { + var pointer = this.scene.input.mousePointer; + return new Vec2(Math.round((pointer.x - this.x) / 3), Math.round((pointer.y - this.y) / 3)); + }; + return UIContainer; +}(Phaser.GameObjects.Container)); var UIHistoryManipulation = /** @class */ (function (_super) { __extends(UIHistoryManipulation, _super); function UIHistoryManipulation(scene, x, y) { @@ -981,3 +1439,266 @@ var UIModeSwitchButton = /** @class */ (function (_super) { }; return UIModeSwitchButton; }(UIComponent)); +var UISideMenuButton = /** @class */ (function (_super) { + __extends(UISideMenuButton, _super); + function UISideMenuButton(scene, x, y) { + var _this = _super.call(this, scene, x, y, "ui_button_side_menu") || this; + _this.scene = scene; + _this.setActive(true); + return _this; + } + UISideMenuButton.prototype.update = function () { + if (this.mouseIntersects()) { + if (this.scene.input.mousePointer.leftButtonDown()) { + this.setFrame(2); + } + else + this.setFrame(1); + } + else { + this.setFrame(0); + } + }; + return UISideMenuButton; +}(UIComponent)); +var UISidebar = /** @class */ (function (_super) { + __extends(UISidebar, _super); + function UISidebar(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.backgrounds = []; + _this.elems = []; + _this.sprites = []; + _this.hoveredElem = null; + _this.scene = scene; + for (var i = 0; i < 15; i++) { + var background = new Phaser.GameObjects.Sprite(_this.scene, 0, 21 * 3 * i, "ui_sidebar_bg", 1); + background.setScale(3); + background.setOrigin(0, 0); + _this.backgrounds.push(background); + _this.list.push(background); + } + _this.activeSpriteCursor = new Phaser.GameObjects.Sprite(_this.scene, 9, 9, "ui_sidebar_cursor"); + _this.activeSpriteCursor.setScale(3); + _this.activeSpriteCursor.setOrigin(0); + _this.list.push(_this.activeSpriteCursor); + _this.hoverSpriteCursor = new Phaser.GameObjects.Sprite(_this.scene, 3, 3, "ui_sidebar_cursor"); + _this.hoverSpriteCursor.setScale(3); + _this.hoverSpriteCursor.setOrigin(0); + _this.hoverSpriteCursor.setAlpha(0.35); + _this.hoverSpriteCursor.setVisible(false); + _this.list.push(_this.hoverSpriteCursor); + return _this; + } + UISidebar.prototype.mouseIntersects = function () { + return (this.mousePos().x < 69); + }; + UISidebar.prototype.update = function () { + var hovered = undefined; + if (this.mouseIntersects()) { + if (this.mousePos().x % 21 >= 4 && this.mousePos().y % 21 >= 4) { + var mousePos = this.mousePos(); + var x = Math.floor(mousePos.x / 21); + var y = Math.floor(mousePos.y / 21); + hovered = this.sprites[x + y * 3]; + if (hovered != undefined) { + this.hoverSpriteCursor.setVisible(true); + this.hoverSpriteCursor.setPosition(9 + x * 21 * 3, 9 + y * 21 * 3); + } + else { + this.hoverSpriteCursor.setVisible(false); + return; + } + if (hovered == undefined && this.hoveredElem != null) { + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + this.hoveredElem = null; + return; + } + if (this.hoveredElem != null && this.hoveredElem.x != x && this.hoveredElem.y != y) + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + this.elemHover(x, y); + this.hoveredElem = new Vec2(x, y); + if (this.scene.input.mousePointer.leftButtonDown()) { + this.activeSpriteCursor.setPosition(9 + x * 21 * 3, 9 + y * 21 * 3); + this.elemClick(x, y); + } + } + else { + if (this.hoveredElem != null) + this.elemUnhover(this.hoveredElem.x, this.hoveredElem.y); + this.hoveredElem = null; + this.hoverSpriteCursor.setVisible(false); + } + } + else + this.hoverSpriteCursor.setVisible(false); + }; + UISidebar.prototype.elemHover = function (x, y) { }; + UISidebar.prototype.elemUnhover = function (x, y) { }; + UISidebar.prototype.elemClick = function (x, y) { }; + return UISidebar; +}(UIContainer)); +var UITileSelector = /** @class */ (function (_super) { + __extends(UITileSelector, _super); + function UITileSelector(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.tiles = []; + _this.scene = scene; + _this.background = new Phaser.GameObjects.Sprite(_this.scene, 0, 0, "ui_quick_selector"); + _this.background.setScale(3, 3); + _this.background.setOrigin(0, 0); + _this.intersects.push(_this.background); + _this.add(_this.background); + _this.selectSprite = new Phaser.GameObjects.Sprite(_this.scene, 0, 0, "cursor"); + _this.selectSprite.setScale(3, 3); + _this.selectSprite.setOrigin(0, 0); + _this.add(_this.selectSprite); + _this.positionSelect(0); + return _this; + } + UITileSelector.prototype.positionSelect = function (slot) { + this.selectSprite.setPosition(12, 18 + slot * 60); + }; + UITileSelector.prototype.update = function () { + if (this.mouseIntersects() && this.scene.input.mousePointer.leftButtonDown()) { + var mousePos = this.mousePos(); + if (mousePos.x < 4 || mousePos.x > 4 + 16) + return; + mousePos.y -= 6; + if (mousePos.y % 20 > 16) + return; + var slot = Math.floor(mousePos.y / 20); + if (slot < 0 || slot >= this.tiles.length) + return; + this.scene.activePalette = this.tiles[slot]; + this.positionSelect(slot); + } + }; + UITileSelector.prototype.addTile = function (tile) { + var pos = this.tiles.length; + this.tiles.push(tile); + var spr = new Phaser.GameObjects.Sprite(this.scene, 12 - 22 * 2, 18 - 22 * 2 + pos * 60, "tileset_" + tile); + spr.setOrigin(0, 0); + spr.setCrop(22, 22, 24, 24); + spr.setScale(2); + this.add(spr); + this.sendToBack(spr); + this.sendToBack(this.background); + }; + return UITileSelector; +}(UIContainer)); +var UITileSidebar = /** @class */ (function (_super) { + __extends(UITileSidebar, _super); + function UITileSidebar(scene, x, y) { + return _super.call(this, scene, x, y) || this; + } + UITileSidebar.prototype.elemClick = function (x, y) { + this.scene.activePalette = this.elems[x + y * 3]; + }; + UITileSidebar.prototype.addPalette = function (tile) { + var p = this.elems.length; + var x = p % 3; + var y = Math.floor(p / 3); + this.elems.push(tile); + var spr = new Phaser.GameObjects.Sprite(this.scene, 12 + x * 21 * 3 - 22 * 2, 12 + y * 21 * 3 - 22 * 2, "tileset_" + tile); + spr.setOrigin(0, 0); + spr.setCrop(21, 21, 26, 26); + spr.setScale(2); + this.sprites.push(spr); + this.list.push(spr); + var spr2 = new Phaser.GameObjects.Sprite(this.scene, 9 + x * 21 * 3, 9 + y * 21 * 3, "ui_sidebar_overlay"); + spr2.setScale(3); + spr2.setOrigin(0, 0); + this.list.push(spr2); + this.bringToTop(this.hoverSpriteCursor); + this.bringToTop(this.activeSpriteCursor); + }; + return UITileSidebar; +}(UISidebar)); +var UITokenSelector = /** @class */ (function (_super) { + __extends(UITokenSelector, _super); + function UITokenSelector(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.tokens = []; + _this.scene = scene; + _this.background = new Phaser.GameObjects.Sprite(_this.scene, 0, 0, "ui_quick_selector"); + _this.background.setScale(3, 3); + _this.background.setOrigin(0, 0); + _this.intersects.push(_this.background); + _this.add(_this.background); + _this.selectSprite = new Phaser.GameObjects.Sprite(_this.scene, 0, 0, "cursor"); + _this.selectSprite.setScale(3, 3); + _this.selectSprite.setOrigin(0, 0); + _this.add(_this.selectSprite); + _this.positionSelect(0); + return _this; + } + UITokenSelector.prototype.positionSelect = function (slot) { + this.selectSprite.setPosition(12, 18 + slot * 60); + }; + UITokenSelector.prototype.update = function () { + if (this.mouseIntersects() && this.scene.input.mousePointer.leftButtonDown()) { + var mousePos = this.mousePos(); + if (mousePos.x < 4 || mousePos.x > 4 + 16) + return; + mousePos.y -= 6; + if (mousePos.y % 20 > 16) + return; + var slot = Math.floor(mousePos.y / 20); + if (slot < 0 || slot >= this.tokens.length) + return; + this.scene.activeToken = this.tokens[slot]; + this.positionSelect(slot); + } + }; + UITokenSelector.prototype.addToken = function (sprite) { + var pos = this.tokens.length; + this.tokens.push(sprite); + var spr = new Phaser.GameObjects.Sprite(this.scene, 12 - 3, 18 - 3 + pos * 60, sprite); + spr.setOrigin(0, 0); + spr.setScale(3); + this.add(spr); + this.sendToBack(spr); + this.sendToBack(this.background); + }; + return UITokenSelector; +}(UIContainer)); +var UITokenSidebar = /** @class */ (function (_super) { + __extends(UITokenSidebar, _super); + function UITokenSidebar(scene, x, y) { + var _this = _super.call(this, scene, x, y) || this; + _this.spinTimer = 0; + return _this; + } + UITokenSidebar.prototype.elemHover = function (x, y) { + var hoveredToken = this.sprites[x + y * 3]; + this.spinTimer++; + if (this.spinTimer > 20) { + var frame = hoveredToken.getFrame() + 1; + frame %= hoveredToken.frameCount(); + hoveredToken.setFrame(frame); + this.spinTimer = 0; + } + }; + UITokenSidebar.prototype.elemUnhover = function (x, y) { + this.sprites.forEach(function (t) { return t.setFrame(0); }); + }; + UITokenSidebar.prototype.elemClick = function (x, y) { + this.scene.activeToken = this.elems[x + y * 3]; + }; + UITokenSidebar.prototype.addToken = function (sprite) { + var p = this.elems.length; + var x = p % 3; + var y = Math.floor(p / 3); + this.elems.push(sprite); + if (x == 0) + this.backgrounds[y].setFrame(0); + var token = new Token(this.scene, 0, 0, sprite); + Phaser.GameObjects.Sprite.prototype.setPosition.call(token, 12 + x * 21 * 3, 12 + y * 21 * 3); + token.setScale(3 / 4); + this.sprites.push(token); + this.list.push(token); + this.bringToTop(this.activeSpriteCursor); + this.bringToTop(this.hoverSpriteCursor); + }; + return UITokenSidebar; +}(UISidebar));