1
0
forked from noxious/client

Renamed zone > map

This commit is contained in:
Dennis Postma 2025-01-02 17:31:31 +01:00
parent 736ddddc54
commit 40c87f0ee3
65 changed files with 762 additions and 762 deletions

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 325 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 847 B

After

Width:  |  Height:  |  Size: 847 B

View File

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 745 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 109 B

View File

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 696 B

View File

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 708 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 453 KiB

View File

@ -10,27 +10,27 @@ import GmPanel from '@/components/gameMaster/GmPanel.vue'
import Characters from '@/components/screens/Characters.vue' import Characters from '@/components/screens/Characters.vue'
import Game from '@/components/screens/Game.vue' import Game from '@/components/screens/Game.vue'
import Login from '@/components/screens/Login.vue' import Login from '@/components/screens/Login.vue'
import ZoneEditor from '@/components/screens/ZoneEditor.vue' import MapEditor from '@/components/screens/MapEditor.vue'
import BackgroundImageLoader from '@/components/utilities/BackgroundImageLoader.vue' import BackgroundImageLoader from '@/components/utilities/BackgroundImageLoader.vue'
import Notifications from '@/components/utilities/Notifications.vue' import Notifications from '@/components/utilities/Notifications.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, watch } from 'vue' import { computed, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const currentScreen = computed(() => { const currentScreen = computed(() => {
if (!gameStore.connection) return Login if (!gameStore.connection) return Login
if (!gameStore.token) return Login if (!gameStore.token) return Login
if (!gameStore.character) return Characters if (!gameStore.character) return Characters
if (zoneEditorStore.active) return ZoneEditor if (mapEditorStore.active) return MapEditor
return Game return Game
}) })
// Watch zoneEditorStore.active and empty gameStore.game.loadedAssets // Watch mapEditorStore.active and empty gameStore.game.loadedAssets
watch( watch(
() => zoneEditorStore.active, () => mapEditorStore.active,
() => { () => {
gameStore.game.loadedAssets = [] gameStore.game.loadedAssets = []
} }

View File

@ -46,7 +46,7 @@ export type Object = {
frameHeight: number frameHeight: number
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
ZoneObject: ZoneObject[] MapObject: PlacedMapObject[]
} }
export type Item = { export type Item = {
@ -65,34 +65,34 @@ export type Item = {
export type ItemType = 'WEAPON' | 'HELMET' | 'CHEST' | 'LEGS' | 'BOOTS' | 'GLOVES' | 'RING' | 'NECKLACE' export type ItemType = 'WEAPON' | 'HELMET' | 'CHEST' | 'LEGS' | 'BOOTS' | 'GLOVES' | 'RING' | 'NECKLACE'
export type ItemRarity = 'COMMON' | 'UNCOMMON' | 'RARE' | 'EPIC' | 'LEGENDARY' export type ItemRarity = 'COMMON' | 'UNCOMMON' | 'RARE' | 'EPIC' | 'LEGENDARY'
export type Zone = { export type Map = {
id: UUID id: UUID
name: string name: string
width: number width: number
height: number height: number
tiles: any | null tiles: any | null
pvp: boolean pvp: boolean
zoneEffects: ZoneEffect[] mapEffects: MapEffect[]
zoneEventTiles: ZoneEventTile[] mapEventTiles: MapEventTile[]
zoneObjects: ZoneObject[] mapObjects: PlacedMapObject[]
characters: Character[] characters: Character[]
chats: Chat[] chats: Chat[]
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
} }
export type ZoneEffect = { export type MapEffect = {
id: UUID id: UUID
zoneId: UUID mapId: UUID
zone: Zone map: Map
effect: string effect: string
strength: number strength: number
} }
export type ZoneObject = { export type PlacedMapObject = {
id: UUID id: UUID
zoneId: UUID mapId: UUID
zone: Zone map: Map
objectId: UUID objectId: UUID
object: Object object: Object
depth: number depth: number
@ -101,29 +101,29 @@ export type ZoneObject = {
positionY: number positionY: number
} }
export enum ZoneEventTileType { export enum MapEventTileType {
BLOCK = 'BLOCK', BLOCK = 'BLOCK',
TELEPORT = 'TELEPORT', TELEPORT = 'TELEPORT',
NPC = 'NPC', NPC = 'NPC',
ITEM = 'ITEM' ITEM = 'ITEM'
} }
export type ZoneEventTile = { export type MapEventTile = {
id: UUID id: UUID
zoneId: UUID mapId: UUID
zone: Zone map: Map
type: ZoneEventTileType type: MapEventTileType
positionX: number positionX: number
positionY: number positionY: number
teleport?: ZoneEventTileTeleport teleport?: MapEventTileTeleport
} }
export type ZoneEventTileTeleport = { export type MapEventTileTeleport = {
id: UUID id: UUID
zoneEventTileId: UUID mapEventTileId: UUID
zoneEventTile: ZoneEventTile mapEventTile: MapEventTile
toZoneId: UUID toMapId: UUID
toZone: Zone toMap: Map
toPositionX: number toPositionX: number
toPositionY: number toPositionY: number
toRotation: number toRotation: number
@ -188,14 +188,14 @@ export type Character = {
characterType: CharacterType | null | string characterType: CharacterType | null | string
characterHairId: UUID | null characterHairId: UUID | null
characterHair: CharacterHair | null characterHair: CharacterHair | null
zoneId: UUID mapId: UUID
zone: Zone map: Map
chats: Chat[] chats: Chat[]
items: CharacterItem[] items: CharacterItem[]
equipment: CharacterEquipment[] equipment: CharacterEquipment[]
} }
export type ZoneCharacter = { export type MapCharacter = {
character: Character character: Character
isMoving?: boolean isMoving?: boolean
} }
@ -252,8 +252,8 @@ export type Chat = {
id: UUID id: UUID
characterId: UUID characterId: UUID
character: Character character: Character
zoneId: UUID mapId: UUID
zone: Zone map: Map
message: string message: string
createdAt: Date createdAt: Date
} }
@ -272,7 +272,7 @@ export type WeatherState = {
fogDensity: number fogDensity: number
} }
export type zoneLoadData = { export type mapLoadData = {
zone: Zone map: Map
characters: ZoneCharacter[] characters: MapCharacter[]
} }

View File

@ -5,7 +5,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { WeatherState } from '@/application/types' import type { WeatherState } from '@/application/types'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useMapStore } from '@/stores/mapStore'
import { Scene } from 'phavuer' import { Scene } from 'phavuer'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue' import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -19,9 +19,9 @@ const LIGHT_CONFIG = {
// Stores and refs // Stores and refs
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneStore = useZoneStore() const mapStore = useMapStore()
const sceneRef = ref<Phaser.Scene | null>(null) const sceneRef = ref<Phaser.Scene | null>(null)
const zoneEffectsReady = ref(false) const mapEffectsReady = ref(false)
// Effect objects // Effect objects
const effects = { const effects = {
@ -80,7 +80,7 @@ const initializeEffects = (scene: Phaser.Scene) => {
// Effect updates // Effect updates
const updateScene = () => { const updateScene = () => {
const timeBasedLight = calculateLightStrength(gameStore.world.date) const timeBasedLight = calculateLightStrength(gameStore.world.date)
const zoneEffects = zoneStore.zone?.zoneEffects?.reduce( const mapEffects = mapStore.map?.mapEffects?.reduce(
(acc, curr) => ({ (acc, curr) => ({
...acc, ...acc,
[curr.effect]: curr.strength [curr.effect]: curr.strength
@ -88,18 +88,18 @@ const updateScene = () => {
{} {}
) as { [key: string]: number } ) as { [key: string]: number }
// Only update effects once zoneEffects are loaded // Only update effects once mapEffects are loaded
if (!zoneEffectsReady.value) { if (!mapEffectsReady.value) {
if (zoneEffects && Object.keys(zoneEffects).length) { if (mapEffects && Object.keys(mapEffects).length) {
zoneEffectsReady.value = true mapEffectsReady.value = true
} else { } else {
return return
} }
} }
const finalEffects = const finalEffects =
zoneEffects && Object.keys(zoneEffects).length mapEffects && Object.keys(mapEffects).length
? zoneEffects ? mapEffects
: { : {
light: timeBasedLight, light: timeBasedLight,
rain: weatherState.value.isRainEnabled ? weatherState.value.rainPercentage : 0, rain: weatherState.value.isRainEnabled ? weatherState.value.rainPercentage : 0,
@ -161,9 +161,9 @@ const handleResize = () => {
// Lifecycle // Lifecycle
watch( watch(
() => zoneStore.zone, () => mapStore.map,
() => { () => {
zoneEffectsReady.value = false mapEffectsReady.value = false
updateScene() updateScene()
}, },
{ deep: true } { deep: true }

View File

@ -1,23 +1,23 @@
<template> <template>
<ChatBubble :zoneCharacter="props.zoneCharacter" :currentX="currentX" :currentY="currentY" /> <ChatBubble :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />
<Healthbar :zoneCharacter="props.zoneCharacter" :currentX="currentX" :currentY="currentY" /> <Healthbar :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />
<Container ref="charContainer" :depth="isometricDepth" :x="currentX" :y="currentY"> <Container ref="charContainer" :depth="isometricDepth" :x="currentX" :y="currentY">
<CharacterHair :zoneCharacter="props.zoneCharacter" :currentX="currentX" :currentY="currentY" /> <CharacterHair :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />
<!-- <CharacterChest :zoneCharacter="props.zoneCharacter" :currentX="currentX" :currentY="currentY" />--> <!-- <CharacterChest :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />-->
<Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" /> <Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" />
</Container> </Container>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import config from '@/application/config' import config from '@/application/config'
import { type Sprite as SpriteT, type ZoneCharacter } from '@/application/types' import { type Sprite as SpriteT, type MapCharacter } from '@/application/types'
import CharacterHair from '@/components/game/character/partials/CharacterHair.vue' import CharacterHair from '@/components/game/character/partials/CharacterHair.vue'
import ChatBubble from '@/components/game/character/partials/ChatBubble.vue' import ChatBubble from '@/components/game/character/partials/ChatBubble.vue'
import Healthbar from '@/components/game/character/partials/Healthbar.vue' import Healthbar from '@/components/game/character/partials/Healthbar.vue'
import { loadSpriteTextures } from '@/composables/gameComposable' import { loadSpriteTextures } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useMapStore } from '@/stores/mapStore'
import { Container, refObj, Sprite, useScene } from 'phavuer' import { Container, refObj, Sprite, useScene } from 'phavuer'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
@ -31,14 +31,14 @@ enum Direction {
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
zoneCharacter: ZoneCharacter mapCharacter: MapCharacter
}>() }>()
const charContainer = refObj<Phaser.GameObjects.Container>() const charContainer = refObj<Phaser.GameObjects.Container>()
const charSprite = refObj<Phaser.GameObjects.Sprite>() const charSprite = refObj<Phaser.GameObjects.Sprite>()
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneStore = useZoneStore() const mapStore = useMapStore()
const scene = useScene() const scene = useScene()
const currentX = ref(0) const currentX = ref(0)
@ -105,19 +105,19 @@ const calcDirection = (oldX: number, oldY: number, newX: number, newY: number):
return Direction.UNCHANGED return Direction.UNCHANGED
} }
const isFlippedX = computed(() => [6, 4].includes(props.zoneCharacter.character.rotation ?? 0)) const isFlippedX = computed(() => [6, 4].includes(props.mapCharacter.character.rotation ?? 0))
const charTexture = computed(() => { const charTexture = computed(() => {
const { rotation, characterType } = props.zoneCharacter.character const { rotation, characterType } = props.mapCharacter.character
const spriteId = characterType?.sprite ?? 'idle_right_down' const spriteId = characterType?.sprite ?? 'idle_right_down'
const action = props.zoneCharacter.isMoving ? 'walk' : 'idle' const action = props.mapCharacter.isMoving ? 'walk' : 'idle'
const direction = [0, 6].includes(rotation) ? 'left_up' : 'right_down' const direction = [0, 6].includes(rotation) ? 'left_up' : 'right_down'
return `${spriteId}-${action}_${direction}` return `${spriteId}-${action}_${direction}`
}) })
const updateSprite = () => { const updateSprite = () => {
if (props.zoneCharacter.isMoving) { if (props.mapCharacter.isMoving) {
charSprite.value!.anims.play(charTexture.value, true) charSprite.value!.anims.play(charTexture.value, true)
return return
} }
@ -129,10 +129,10 @@ const updateSprite = () => {
watch( watch(
() => ({ () => ({
x: props.zoneCharacter.character.positionX, x: props.mapCharacter.character.positionX,
y: props.zoneCharacter.character.positionY, y: props.mapCharacter.character.positionY,
isMoving: props.zoneCharacter.isMoving, isMoving: props.mapCharacter.isMoving,
rotation: props.zoneCharacter.character.rotation rotation: props.mapCharacter.character.rotation
}), }),
(newValues, oldValues) => { (newValues, oldValues) => {
if (!newValues) return if (!newValues) return
@ -150,9 +150,9 @@ watch(
{ deep: true } { deep: true }
) )
watch(() => props.zoneCharacter, updateSprite) watch(() => props.mapCharacter, updateSprite)
loadSpriteTextures(scene, props.zoneCharacter.character.characterType?.sprite as string) loadSpriteTextures(scene, props.mapCharacter.character.characterType?.sprite as string)
.then(() => { .then(() => {
charSprite.value!.setTexture(charTexture.value) charSprite.value!.setTexture(charTexture.value)
charSprite.value!.setFlipX(isFlippedX.value) charSprite.value!.setFlipX(isFlippedX.value)
@ -162,17 +162,17 @@ loadSpriteTextures(scene, props.zoneCharacter.character.characterType?.sprite as
}) })
onMounted(() => { onMounted(() => {
charContainer.value!.setName(props.zoneCharacter.character!.name) charContainer.value!.setName(props.mapCharacter.character!.name)
if (props.zoneCharacter.character.id === gameStore.character!.id) { if (props.mapCharacter.character.id === gameStore.character!.id) {
zoneStore.setCharacterLoaded(true) mapStore.setCharacterLoaded(true)
// #146 : Set camera position to character, need to be improved still // #146 : Set camera position to character, need to be improved still
// scene.cameras.main.startFollow(charContainer.value as Phaser.GameObjects.Container) // scene.cameras.main.startFollow(charContainer.value as Phaser.GameObjects.Container)
// scene.cameras.main.stopFollow() // scene.cameras.main.stopFollow()
} }
updatePosition(props.zoneCharacter.character.positionX, props.zoneCharacter.character.positionY, props.zoneCharacter.character.rotation) updatePosition(props.mapCharacter.character.positionX, props.mapCharacter.character.positionY, props.mapCharacter.character.rotation)
}) })
onUnmounted(() => { onUnmounted(() => {

View File

@ -3,14 +3,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type { Sprite as SpriteT, ZoneCharacter } from '@/application/types' import type { Sprite as SpriteT, MapCharacter } from '@/application/types'
import { loadSpriteTextures } from '@/composables/gameComposable' import { loadSpriteTextures } from '@/composables/gameComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps<{ const props = defineProps<{
zoneCharacter: ZoneCharacter mapCharacter: MapCharacter
currentX: number currentX: number
currentY: number currentY: number
}>() }>()
@ -19,19 +19,19 @@ const gameStore = useGameStore()
const scene = useScene() const scene = useScene()
const texture = computed(() => { const texture = computed(() => {
const { rotation, characterHair } = props.zoneCharacter.character const { rotation, characterHair } = props.mapCharacter.character
const spriteId = characterHair?.sprite?.id const spriteId = characterHair?.sprite?.id
const direction = [0, 6].includes(rotation) ? 'back' : 'front' const direction = [0, 6].includes(rotation) ? 'back' : 'front'
return `${spriteId}-${direction}` return `${spriteId}-${direction}`
}) })
const isFlippedX = computed(() => [6, 4].includes(props.zoneCharacter.character.rotation ?? 0)) const isFlippedX = computed(() => [6, 4].includes(props.mapCharacter.character.rotation ?? 0))
const imageProps = computed(() => { const imageProps = computed(() => {
// Get the current sprite action based on direction // Get the current sprite action based on direction
const direction = [0, 6].includes(props.zoneCharacter.character.rotation ?? 0) ? 'back' : 'front' const direction = [0, 6].includes(props.mapCharacter.character.rotation ?? 0) ? 'back' : 'front'
const spriteAction = props.zoneCharacter.character.characterHair?.sprite?.spriteActions?.find((spriteAction) => spriteAction.action === direction) const spriteAction = props.mapCharacter.character.characterHair?.sprite?.spriteActions?.find((spriteAction) => spriteAction.action === direction)
return { return {
depth: 1, depth: 1,
@ -39,11 +39,11 @@ const imageProps = computed(() => {
originY: Number(spriteAction?.originY) ?? 0, originY: Number(spriteAction?.originY) ?? 0,
flipX: isFlippedX.value, flipX: isFlippedX.value,
texture: texture.value texture: texture.value
// y: props.zoneCharacter.isMoving ? Math.floor(Date.now() / 250) % 2 : 0 // y: props.mapCharacter.isMoving ? Math.floor(Date.now() / 250) % 2 : 0
} }
}) })
loadSpriteTextures(scene, props.zoneCharacter.character.characterHair?.sprite as SpriteT) loadSpriteTextures(scene, props.mapCharacter.character.characterHair?.sprite as SpriteT)
.then(() => {}) .then(() => {})
.catch((error) => { .catch((error) => {
console.error('Error loading texture:', error) console.error('Error loading texture:', error)

View File

@ -3,14 +3,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type { Sprite as SpriteT, ZoneCharacter } from '@/application/types' import type { Sprite as SpriteT, MapCharacter } from '@/application/types'
import { loadSpriteTextures } from '@/composables/gameComposable' import { loadSpriteTextures } from '@/composables/gameComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { computed } from 'vue' import { computed } from 'vue'
const props = defineProps<{ const props = defineProps<{
zoneCharacter: ZoneCharacter mapCharacter: MapCharacter
currentX: number currentX: number
currentY: number currentY: number
}>() }>()
@ -19,19 +19,19 @@ const gameStore = useGameStore()
const scene = useScene() const scene = useScene()
const texture = computed(() => { const texture = computed(() => {
const { rotation, characterHair } = props.zoneCharacter.character const { rotation, characterHair } = props.mapCharacter.character
const spriteId = characterHair?.sprite?.id const spriteId = characterHair?.sprite?.id
const direction = [0, 6].includes(rotation) ? 'back' : 'front' const direction = [0, 6].includes(rotation) ? 'back' : 'front'
return `${spriteId}-${direction}` return `${spriteId}-${direction}`
}) })
const isFlippedX = computed(() => [6, 4].includes(props.zoneCharacter.character.rotation ?? 0)) const isFlippedX = computed(() => [6, 4].includes(props.mapCharacter.character.rotation ?? 0))
const imageProps = computed(() => { const imageProps = computed(() => {
// Get the current sprite action based on direction // Get the current sprite action based on direction
const direction = [0, 6].includes(props.zoneCharacter.character.rotation ?? 0) ? 'back' : 'front' const direction = [0, 6].includes(props.mapCharacter.character.rotation ?? 0) ? 'back' : 'front'
const spriteAction = props.zoneCharacter.character.characterHair?.sprite?.spriteActions?.find((spriteAction) => spriteAction.action === direction) const spriteAction = props.mapCharacter.character.characterHair?.sprite?.spriteActions?.find((spriteAction) => spriteAction.action === direction)
return { return {
depth: 1, depth: 1,
@ -39,11 +39,11 @@ const imageProps = computed(() => {
originY: Number(spriteAction?.originY) ?? 0, originY: Number(spriteAction?.originY) ?? 0,
flipX: isFlippedX.value, flipX: isFlippedX.value,
texture: texture.value, texture: texture.value,
y: props.zoneCharacter.isMoving ? Math.floor(Date.now() / 250) % 2 : 0 y: props.mapCharacter.isMoving ? Math.floor(Date.now() / 250) % 2 : 0
} }
}) })
loadSpriteTextures(scene, props.zoneCharacter.character.characterHair?.sprite as SpriteT) loadSpriteTextures(scene, props.mapCharacter.character.characterHair?.sprite as SpriteT)
.then(() => {}) .then(() => {})
.catch((error) => { .catch((error) => {
console.error('Error loading texture:', error) console.error('Error loading texture:', error)

View File

@ -6,12 +6,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ZoneCharacter } from '@/application/types' import type { MapCharacter } from '@/application/types'
import { Container, refObj, RoundRectangle, Text, useGame } from 'phavuer' import { Container, refObj, RoundRectangle, Text, useGame } from 'phavuer'
import { onMounted } from 'vue' import { onMounted } from 'vue'
const props = defineProps<{ const props = defineProps<{
zoneCharacter: ZoneCharacter mapCharacter: MapCharacter
currentX: number currentX: number
currentY: number currentY: number
}>() }>()
@ -20,11 +20,11 @@ const game = useGame()
const charChatContainer = refObj<Phaser.GameObjects.Container>() const charChatContainer = refObj<Phaser.GameObjects.Container>()
const createChatBubble = (container: Phaser.GameObjects.Container) => { const createChatBubble = (container: Phaser.GameObjects.Container) => {
container.setName(`${props.zoneCharacter.character.name}_chatBubble`) container.setName(`${props.mapCharacter.character.name}_chatBubble`)
} }
const createChatText = (text: Phaser.GameObjects.Text) => { const createChatText = (text: Phaser.GameObjects.Text) => {
text.setName(`${props.zoneCharacter.character.name}_chatText`) text.setName(`${props.mapCharacter.character.name}_chatText`)
text.setFontSize(13) text.setFontSize(13)
text.setFontFamily('Arial') text.setFontFamily('Arial')
text.setOrigin(0.5, 10.9) text.setOrigin(0.5, 10.9)
@ -40,7 +40,7 @@ const createChatText = (text: Phaser.GameObjects.Text) => {
} }
onMounted(() => { onMounted(() => {
charChatContainer.value!.setName(`${props.zoneCharacter.character!.name}_chatContainer`) charChatContainer.value!.setName(`${props.mapCharacter.character!.name}_chatContainer`)
charChatContainer.value!.setVisible(false) charChatContainer.value!.setVisible(false)
}) })
</script> </script>

View File

@ -1,17 +1,17 @@
<template> <template>
<Container :depth="999" :x="currentX" :y="currentY"> <Container :depth="999" :x="currentX" :y="currentY">
<Text @create="createNicknameText" :text="props.zoneCharacter.character.name" /> <Text @create="createNicknameText" :text="props.mapCharacter.character.name" />
<RoundRectangle :origin-x="0.5" :origin-y="18.5" :fillColor="0xffffff" :width="74" :height="6" :radius="5" /> <RoundRectangle :origin-x="0.5" :origin-y="18.5" :fillColor="0xffffff" :width="74" :height="6" :radius="5" />
<RoundRectangle :origin-x="0.5" :origin-y="36.4" :fillColor="0x00b3b3" :width="70" :height="3" :radius="5" /> <RoundRectangle :origin-x="0.5" :origin-y="36.4" :fillColor="0x00b3b3" :width="70" :height="3" :radius="5" />
</Container> </Container>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ZoneCharacter } from '@/application/types' import type { MapCharacter } from '@/application/types'
import { Container, RoundRectangle, Text, useGame } from 'phavuer' import { Container, RoundRectangle, Text, useGame } from 'phavuer'
const props = defineProps<{ const props = defineProps<{
zoneCharacter: ZoneCharacter mapCharacter: MapCharacter
currentX: number currentX: number
currentY: number currentY: number
}>() }>()

View File

@ -0,0 +1,14 @@
<template>
<Character v-for="item in mapStore.characters" :key="item.character.id" :tilemap="tilemap" :mapCharacter="item" />
</template>
<script setup lang="ts">
import Character from '@/components/game/character/Character.vue'
import { useMapStore } from '@/stores/mapStore'
const mapStore = useMapStore()
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
}>()
</script>

View File

@ -0,0 +1,50 @@
<template>
<MapTiles :key="mapStore.map?.id ?? 0" @tileMap:create="tileMap = $event" />
<MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Characters v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
</template>
<script setup lang="ts">
import type { MapCharacter, mapLoadData } from '@/application/types'
import Characters from '@/components/game/map/Characters.vue'
import MapObjects from '@/components/game/map/MapObjects.vue'
import MapTiles from '@/components/game/map/MapTiles.vue'
import { loadMapTilesIntoScene } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore'
import { useScene } from 'phavuer'
import { onUnmounted, ref } from 'vue'
const scene = useScene()
const gameStore = useGameStore()
const mapStore = useMapStore()
const tileMap = ref(null as Phaser.Tilemaps.Tilemap | null)
onUnmounted(() => {
mapStore.reset()
gameStore.connection!.off('map:character:teleport')
gameStore.connection!.off('map:character:join')
gameStore.connection!.off('map:character:leave')
gameStore.connection!.off('map:character:move')
})
// Event listeners
gameStore.connection!.on('map:character:teleport', async (data: mapLoadData) => {
await loadMapTilesIntoScene(data.map.id, scene)
mapStore.setMap(data.map)
mapStore.setCharacters(data.characters)
})
gameStore.connection!.on('map:character:join', async (data: MapCharacter) => {
mapStore.addCharacter(data)
})
gameStore.connection!.on('map:character:leave', (characterId: number) => {
mapStore.removeCharacter(characterId)
})
gameStore.connection!.on('map:character:move', (data: { characterId: number; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
mapStore.updateCharacterPosition(data)
})
</script>

View File

@ -0,0 +1,14 @@
<template>
<MapObject v-for="mapObject in mapStore.map?.mapObjects" :tilemap="tilemap" :mapObject />
</template>
<script setup lang="ts">
import MapObject from '@/components/game/map/partials/MapObject.vue'
import { useMapStore } from '@/stores/mapStore'
const mapStore = useMapStore()
defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
}>()
</script>

View File

@ -6,15 +6,15 @@
import config from '@/application/config' import config from '@/application/config'
import { unduplicateArray } from '@/application/utilities' import { unduplicateArray } from '@/application/utilities'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { FlattenZoneArray, setLayerTiles } from '@/composables/zoneComposable' import { FlattenMapArray, setLayerTiles } from '@/composables/mapComposable'
import { useZoneStore } from '@/stores/zoneStore' import { useMapStore } from '@/stores/mapStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onBeforeUnmount } from 'vue' import { onBeforeUnmount } from 'vue'
const emit = defineEmits(['tileMap:create']) const emit = defineEmits(['tileMap:create'])
const scene = useScene() const scene = useScene()
const zoneStore = useZoneStore() const mapStore = useMapStore()
const tileMap = createTileMap() const tileMap = createTileMap()
const tileLayer = createTileLayer() const tileLayer = createTileLayer()
@ -24,16 +24,16 @@ const tileLayer = createTileLayer()
* A map can have one or more tilemap layers, which are the display objects that actually render the tiles. * A map can have one or more tilemap layers, which are the display objects that actually render the tiles.
*/ */
function createTileMap() { function createTileMap() {
const zoneData = new Phaser.Tilemaps.MapData({ const mapData = new Phaser.Tilemaps.MapData({
width: zoneStore.zone?.width, width: mapStore.map?.width,
height: zoneStore.zone?.height, height: mapStore.map?.height,
tileWidth: config.tile_size.x, tileWidth: config.tile_size.x,
tileHeight: config.tile_size.y, tileHeight: config.tile_size.y,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D format: Phaser.Tilemaps.Formats.ARRAY_2D
}) })
const newTileMap = new Phaser.Tilemaps.Tilemap(scene, zoneData) const newTileMap = new Phaser.Tilemaps.Tilemap(scene, mapData)
emit('tileMap:create', newTileMap) emit('tileMap:create', newTileMap)
return newTileMap return newTileMap
@ -43,7 +43,7 @@ function createTileMap() {
* A Tileset is a combination of a single image containing the tiles and a container for data about each tile. * A Tileset is a combination of a single image containing the tiles and a container for data about each tile.
*/ */
function createTileLayer() { function createTileLayer() {
const tilesArray = unduplicateArray(FlattenZoneArray(zoneStore.zone?.tiles ?? [])) const tilesArray = unduplicateArray(FlattenMapArray(mapStore.map?.tiles ?? []))
const tilesetImages = Array.from(tilesArray).map((tile: any, index: number) => { const tilesetImages = Array.from(tilesArray).map((tile: any, index: number) => {
return tileMap.addTilesetImage(tile, tile, config.tile_size.x, config.tile_size.y, 1, 2, index + 1, { x: 0, y: -config.tile_size.y }) return tileMap.addTilesetImage(tile, tile, config.tile_size.x, config.tile_size.y, 1, 2, index + 1, { x: 0, y: -config.tile_size.y })
@ -59,7 +59,7 @@ function createTileLayer() {
return layer return layer
} }
setLayerTiles(tileMap, tileLayer, zoneStore.zone?.tiles) setLayerTiles(tileMap, tileLayer, mapStore.map?.tiles)
onBeforeUnmount(() => { onBeforeUnmount(() => {
tileMap.destroyLayer('tiles') tileMap.destroyLayer('tiles')

View File

@ -0,0 +1,41 @@
<template>
<Image v-if="gameStore.getLoadedAsset(props.mapObject.object.id)" v-bind="imageProps" />
</template>
<script setup lang="ts">
import type { AssetDataT, PlacedMapObject } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer'
import { computed } from 'vue'
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
mapObject: PlacedMapObject
}>()
const gameStore = useGameStore()
const scene = useScene()
const imageProps = computed(() => ({
depth: calculateIsometricDepth(props.mapObject.positionX, props.mapObject.positionY, props.mapObject.object.frameWidth, props.mapObject.object.frameHeight),
x: tileToWorldX(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
y: tileToWorldY(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
flipX: props.mapObject.isRotated,
texture: props.mapObject.object.id,
originY: Number(props.mapObject.object.originX),
originX: Number(props.mapObject.object.originY)
}))
loadTexture(scene, {
key: props.mapObject.object.id,
data: '/assets/objects/' + props.mapObject.object.id + '.png',
group: 'objects',
updatedAt: props.mapObject.object.updatedAt,
frameWidth: props.mapObject.object.frameWidth,
frameHeight: props.mapObject.object.frameHeight
} as AssetDataT).catch((error) => {
console.error('Error loading texture:', error)
})
</script>

View File

@ -1,14 +0,0 @@
<template>
<Character v-for="item in zoneStore.characters" :key="item.character.id" :tilemap="tilemap" :zoneCharacter="item" />
</template>
<script setup lang="ts">
import Character from '@/components/game/character/Character.vue'
import { useZoneStore } from '@/stores/zoneStore'
const zoneStore = useZoneStore()
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
}>()
</script>

View File

@ -1,50 +0,0 @@
<template>
<ZoneTiles :key="zoneStore.zone?.id ?? 0" @tileMap:create="tileMap = $event" />
<ZoneObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Characters v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
</template>
<script setup lang="ts">
import type { ZoneCharacter, zoneLoadData } from '@/application/types'
import Characters from '@/components/game/zone/Characters.vue'
import ZoneObjects from '@/components/game/zone/ZoneObjects.vue'
import ZoneTiles from '@/components/game/zone/ZoneTiles.vue'
import { loadZoneTilesIntoScene } from '@/composables/zoneComposable'
import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore'
import { useScene } from 'phavuer'
import { onUnmounted, ref } from 'vue'
const scene = useScene()
const gameStore = useGameStore()
const zoneStore = useZoneStore()
const tileMap = ref(null as Phaser.Tilemaps.Tilemap | null)
onUnmounted(() => {
zoneStore.reset()
gameStore.connection!.off('zone:character:teleport')
gameStore.connection!.off('zone:character:join')
gameStore.connection!.off('zone:character:leave')
gameStore.connection!.off('zone:character:move')
})
// Event listeners
gameStore.connection!.on('zone:character:teleport', async (data: zoneLoadData) => {
await loadZoneTilesIntoScene(data.zone.id, scene)
zoneStore.setZone(data.zone)
zoneStore.setCharacters(data.characters)
})
gameStore.connection!.on('zone:character:join', async (data: ZoneCharacter) => {
zoneStore.addCharacter(data)
})
gameStore.connection!.on('zone:character:leave', (characterId: number) => {
zoneStore.removeCharacter(characterId)
})
gameStore.connection!.on('zone:character:move', (data: { characterId: number; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
zoneStore.updateCharacterPosition(data)
})
</script>

View File

@ -1,14 +0,0 @@
<template>
<ZoneObject v-for="zoneObject in zoneStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject />
</template>
<script setup lang="ts">
import ZoneObject from '@/components/game/zone/partials/ZoneObject.vue'
import { useZoneStore } from '@/stores/zoneStore'
const zoneStore = useZoneStore()
defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
}>()
</script>

View File

@ -1,41 +0,0 @@
<template>
<Image v-if="gameStore.getLoadedAsset(props.zoneObject.object.id)" v-bind="imageProps" />
</template>
<script setup lang="ts">
import type { AssetDataT, ZoneObject } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer'
import { computed } from 'vue'
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
zoneObject: ZoneObject
}>()
const gameStore = useGameStore()
const scene = useScene()
const imageProps = computed(() => ({
depth: calculateIsometricDepth(props.zoneObject.positionX, props.zoneObject.positionY, props.zoneObject.object.frameWidth, props.zoneObject.object.frameHeight),
x: tileToWorldX(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
y: tileToWorldY(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
flipX: props.zoneObject.isRotated,
texture: props.zoneObject.object.id,
originY: Number(props.zoneObject.object.originX),
originX: Number(props.zoneObject.object.originY)
}))
loadTexture(scene, {
key: props.zoneObject.object.id,
data: '/assets/objects/' + props.zoneObject.object.id + '.png',
group: 'objects',
updatedAt: props.zoneObject.object.updatedAt,
frameWidth: props.zoneObject.object.frameWidth,
frameHeight: props.zoneObject.object.frameHeight
} as AssetDataT).catch((error) => {
console.error('Error loading texture:', error)
})
</script>

View File

@ -6,7 +6,7 @@
<button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Users</button> <button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Users</button>
<button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Chats</button> <button @mousedown.stop class="btn-cyan py-1.5 px-4 min-w-24">Chats</button>
<button @mousedown.stop class="btn-cyan active py-1.5 px-4 min-w-24">Asset manager</button> <button @mousedown.stop class="btn-cyan active py-1.5 px-4 min-w-24">Asset manager</button>
<button class="btn-cyan py-1.5 px-4 min-w-24" type="button" @click="() => zoneEditorStore.toggleActive()">Map editor</button> <button class="btn-cyan py-1.5 px-4 min-w-24" type="button" @click="() => mapEditorStore.toggleActive()">Map editor</button>
</div> </div>
</template> </template>
<template #modalBody> <template #modalBody>
@ -21,11 +21,11 @@
import AssetManager from '@/components/gameMaster/assetManager/AssetManager.vue' import AssetManager from '@/components/gameMaster/assetManager/AssetManager.vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { ref } from 'vue' import { ref } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
let toggle = ref('asset-manager') let toggle = ref('asset-manager')
</script> </script>

View File

@ -25,7 +25,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -25,7 +25,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -22,7 +22,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -55,12 +55,12 @@ import type { Object } from '@/application/types'
import ChipsInput from '@/components/forms/ChipsInput.vue' import ChipsInput from '@/components/forms/ChipsInput.vue'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const assetManagerStore = useAssetManagerStore() const assetManagerStore = useAssetManagerStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const selectedObject = computed(() => assetManagerStore.selectedObject) const selectedObject = computed(() => assetManagerStore.selectedObject)
@ -106,8 +106,8 @@ function refreshObjectList(unsetSelectedObject = true) {
assetManagerStore.setSelectedObject(null) assetManagerStore.setSelectedObject(null)
} }
if (zoneEditorStore.active) { if (mapEditorStore.active) {
zoneEditorStore.setObjectList(response) mapEditorStore.setObjectList(response)
} }
}) })
} }

View File

@ -21,7 +21,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -17,7 +17,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -28,12 +28,12 @@ import type { Tile } from '@/application/types'
import ChipsInput from '@/components/forms/ChipsInput.vue' import ChipsInput from '@/components/forms/ChipsInput.vue'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const assetManagerStore = useAssetManagerStore() const assetManagerStore = useAssetManagerStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const selectedTile = computed(() => assetManagerStore.selectedTile) const selectedTile = computed(() => assetManagerStore.selectedTile)
@ -73,8 +73,8 @@ function refreshTileList(unsetSelectedTile = true) {
assetManagerStore.setSelectedTile(null) assetManagerStore.setSelectedTile(null)
} }
if (zoneEditorStore.active) { if (mapEditorStore.active) {
zoneEditorStore.setTileList(response) mapEditorStore.setTileList(response)
} }
}) })
} }

View File

@ -21,7 +21,7 @@
</div> </div>
<div class="absolute w-12 h-12 bottom-2.5 right-2.5"> <div class="absolute w-12 h-12 bottom-2.5 right-2.5">
<button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop"> <button class="fixed min-w-[unset] w-12 h-12 rounded-md bg-cyan p-0 hover:bg-cyan-800" v-show="hasScrolled" @click="toTop">
<img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/zoneEditor/chevron.svg" alt="" /> <img class="invert w-8 h-8 center-element rotate-180" src="/assets/icons/mapEditor/chevron.svg" alt="" />
</button> </button>
</div> </div>
</div> </div>

View File

@ -0,0 +1,73 @@
<template>
<MapTiles @tileMap:create="tileMap = $event" />
<MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Toolbar @save="save" @clear="clear" />
<MapList />
<TileList />
<ObjectList />
<MapSettings />
<TeleportModal />
</template>
<script setup lang="ts">
import { type Map } from '@/application/types'
import ObjectList from '@/components/gameMaster/mapEditor/partials/ObjectList.vue'
import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
// Components
import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue'
import MapList from '@/components/gameMaster/mapEditor/partials/MapList.vue'
import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.vue'
import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue'
import MapObjects from '@/components/gameMaster/mapEditor/mapPartials/MapObjects.vue'
import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onUnmounted, ref } from 'vue'
const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore()
const tileMap = ref(null as Phaser.Tilemaps.Tilemap | null)
function clear() {
if (!mapEditorStore.map) return
// Clear objects, event tiles and tiles
mapEditorStore.map.mapObjects = []
mapEditorStore.map.mapEventTiles = []
mapEditorStore.triggerClearTiles()
}
function save() {
if (!mapEditorStore.map) return
const data = {
mapId: mapEditorStore.map.id,
name: mapEditorStore.mapSettings.name,
width: mapEditorStore.mapSettings.width,
height: mapEditorStore.mapSettings.height,
tiles: mapEditorStore.map.tiles,
pvp: mapEditorStore.map.pvp,
mapEffects: mapEditorStore.map.mapEffects.map(({ id, mapId, effect, strength }) => ({ id, mapId, effect, strength })),
mapEventTiles: mapEditorStore.map.mapEventTiles.map(({ id, mapId, type, positionX, positionY, teleport }) => ({ id, mapId, type, positionX, positionY, teleport })),
mapObjects: mapEditorStore.map.mapObjects.map(({ id, mapId, objectId, depth, isRotated, positionX, positionY }) => ({ id, mapId, objectId, depth, isRotated, positionX, positionY }))
}
if (mapEditorStore.isSettingsModalShown) {
mapEditorStore.toggleSettingsModal()
}
gameStore.connection?.emit('gm:map_editor:map:update', data, (response: Map) => {
mapEditorStore.setMap(response)
})
}
onUnmounted(() => {
mapEditorStore.reset()
})
</script>

View File

@ -1,23 +1,23 @@
<template> <template>
<Image v-for="tile in zoneEditorStore.zone?.zoneEventTiles" v-bind="getImageProps(tile)" /> <Image v-for="tile in mapEditorStore.map?.mapEventTiles" v-bind="getImageProps(tile)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ZoneEventTileType, type ZoneEventTile } from '@/application/types' import { MapEventTileType, type MapEventTile } from '@/application/types'
import { uuidv4 } from '@/application/utilities' import { uuidv4 } from '@/application/utilities'
import { getTile, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable' import { getTile, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { onMounted, onUnmounted } from 'vue' import { onMounted, onUnmounted } from 'vue'
const scene = useScene() const scene = useScene()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
}>() }>()
function getImageProps(tile: ZoneEventTile) { function getImageProps(tile: MapEventTile) {
return { return {
x: tileToWorldX(props.tilemap, tile.positionX, tile.positionY), x: tileToWorldX(props.tilemap, tile.positionX, tile.positionY),
y: tileToWorldY(props.tilemap, tile.positionX, tile.positionY), y: tileToWorldY(props.tilemap, tile.positionX, tile.positionY),
@ -27,14 +27,14 @@ function getImageProps(tile: ZoneEventTile) {
} }
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is blocking tile or teleport // Check if draw mode is blocking tile or teleport
if (zoneEditorStore.drawMode !== 'blocking tile' && zoneEditorStore.drawMode !== 'teleport') return if (mapEditorStore.drawMode !== 'blocking tile' && mapEditorStore.drawMode !== 'teleport') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -47,42 +47,42 @@ function pencil(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Check if event tile already exists on position // Check if event tile already exists on position
const existingEventTile = zoneEditorStore.zone.zoneEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) const existingEventTile = mapEditorStore.map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y)
if (existingEventTile) return if (existingEventTile) return
// If teleport, check if there is a selected zone // If teleport, check if there is a selected map
if (zoneEditorStore.drawMode === 'teleport' && !zoneEditorStore.teleportSettings.toZoneId) return if (mapEditorStore.drawMode === 'teleport' && !mapEditorStore.teleportSettings.toMapId) return
const newEventTile = { const newEventTile = {
id: uuidv4(), id: uuidv4(),
zoneId: zoneEditorStore.zone.id, mapId: mapEditorStore.map.id,
zone: zoneEditorStore.zone, map: mapEditorStore.map,
type: zoneEditorStore.drawMode === 'blocking tile' ? ZoneEventTileType.BLOCK : ZoneEventTileType.TELEPORT, type: mapEditorStore.drawMode === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
positionX: tile.x, positionX: tile.x,
positionY: tile.y, positionY: tile.y,
teleport: teleport:
zoneEditorStore.drawMode === 'teleport' mapEditorStore.drawMode === 'teleport'
? { ? {
toZoneId: zoneEditorStore.teleportSettings.toZoneId, toMapId: mapEditorStore.teleportSettings.toMapId,
toPositionX: zoneEditorStore.teleportSettings.toPositionX, toPositionX: mapEditorStore.teleportSettings.toPositionX,
toPositionY: zoneEditorStore.teleportSettings.toPositionY, toPositionY: mapEditorStore.teleportSettings.toPositionY,
toRotation: zoneEditorStore.teleportSettings.toRotation toRotation: mapEditorStore.teleportSettings.toRotation
} }
: undefined : undefined
} }
zoneEditorStore.zone.zoneEventTiles = zoneEditorStore.zone.zoneEventTiles.concat(newEventTile as ZoneEventTile) mapEditorStore.map.mapEventTiles = mapEditorStore.map.mapEventTiles.concat(newEventTile as MapEventTile)
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'eraser') return if (mapEditorStore.tool !== 'eraser') return
// Check if draw mode is blocking tile or teleport // Check if draw mode is blocking tile or teleport
if (zoneEditorStore.eraserMode !== 'blocking tile' && zoneEditorStore.eraserMode !== 'teleport') return if (mapEditorStore.eraserMode !== 'blocking tile' && mapEditorStore.eraserMode !== 'teleport') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -95,11 +95,11 @@ function eraser(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Check if event tile already exists on position // Check if event tile already exists on position
const existingEventTile = zoneEditorStore.zone.zoneEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y) const existingEventTile = mapEditorStore.map.mapEventTiles.find((eventTile) => eventTile.positionX === tile.x && eventTile.positionY === tile.y)
if (!existingEventTile) return if (!existingEventTile) return
// Remove existing event tile // Remove existing event tile
zoneEditorStore.zone.zoneEventTiles = zoneEditorStore.zone.zoneEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id) mapEditorStore.map.mapEventTiles = mapEditorStore.map.mapEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id)
} }
onMounted(() => { onMounted(() => {

View File

@ -0,0 +1,45 @@
<template>
<Image v-if="gameStore.getLoadedAsset(props.mapObject.object.id)" v-bind="imageProps" />
</template>
<script setup lang="ts">
import type { AssetDataT, PlacedMapObject } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer'
import { computed } from 'vue'
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
mapObject: PlacedMapObject
selectedMapObject: PlacedMapObject | null
movingMapObject: PlacedMapObject | null
}>()
const gameStore = useGameStore()
const scene = useScene()
const imageProps = computed(() => ({
alpha: props.movingMapObject?.id === props.mapObject.id ? 0.5 : 1,
tint: props.selectedMapObject?.id === props.mapObject.id ? 0x00ff00 : 0xffffff,
depth: calculateIsometricDepth(props.mapObject.positionX, props.mapObject.positionY, props.mapObject.object.frameWidth, props.mapObject.object.frameHeight),
x: tileToWorldX(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
y: tileToWorldY(props.tilemap, props.mapObject.positionX, props.mapObject.positionY),
flipX: props.mapObject.isRotated,
texture: props.mapObject.object.id,
originY: Number(props.mapObject.object.originX),
originX: Number(props.mapObject.object.originY)
}))
loadTexture(scene, {
key: props.mapObject.object.id,
data: '/assets/objects/' + props.mapObject.object.id + '.png',
group: 'objects',
updatedAt: props.mapObject.object.updatedAt,
frameWidth: props.mapObject.object.frameWidth,
frameHeight: props.mapObject.object.frameHeight
} as AssetDataT).catch((error) => {
console.error('Error loading texture:', error)
})
</script>

View File

@ -1,39 +1,39 @@
<template> <template>
<SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" :movingZoneObject="movingZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" /> <SelectedMapObject v-if="selectedMapObject" :mapObject="selectedMapObject" :movingMapObject="movingMapObject" @move="moveMapObject" @rotate="rotateMapObject" @delete="deleteMapObject" />
<ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject :selectedZoneObject :movingZoneObject @pointerup="clickZoneObject(zoneObject)" /> <MapObject v-for="mapObject in mapEditorStore.map?.mapObjects" :tilemap="tilemap" :mapObject :selectedMapObject :movingMapObject @pointerup="clickMapObject(mapObject)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ZoneObject as ZoneObjectT } from '@/application/types' import type { PlacedMapObject as MapObjectT } from '@/application/types'
import { uuidv4 } from '@/application/utilities' import { uuidv4 } from '@/application/utilities'
import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue' import SelectedMapObject from '@/components/gameMaster/mapEditor/partials/SelectedMapObject.vue'
import ZoneObject from '@/components/gameMaster/zoneEditor/zonePartials/ZoneObject.vue' import MapObject from '@/components/gameMaster/mapEditor/mapPartials/MapObject.vue'
import { getTile } from '@/composables/zoneComposable' import { getTile } from '@/composables/mapComposable'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onMounted, onUnmounted, ref, watch } from 'vue' import { onMounted, onUnmounted, ref, watch } from 'vue'
const scene = useScene() const scene = useScene()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const selectedZoneObject = ref<ZoneObjectT | null>(null) const selectedMapObject = ref<MapObjectT | null>(null)
const movingZoneObject = ref<ZoneObjectT | null>(null) const movingMapObject = ref<MapObjectT | null>(null)
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
}>() }>()
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is object // Check if draw mode is object
if (zoneEditorStore.drawMode !== 'object') return if (mapEditorStore.drawMode !== 'object') return
// Check if there is a selected object // Check if there is a selected object
if (!zoneEditorStore.selectedObject) return if (!mapEditorStore.selectedObject) return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -49,34 +49,34 @@ function pencil(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingObject = zoneEditorStore.zone?.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y) const existingObject = mapEditorStore.map?.mapObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
if (existingObject) return if (existingObject) return
const newObject = { const newObject = {
id: uuidv4(), id: uuidv4(),
zoneId: zoneEditorStore.zone.id, mapId: mapEditorStore.map.id,
zone: zoneEditorStore.zone, map: mapEditorStore.map,
objectId: zoneEditorStore.selectedObject.id, objectId: mapEditorStore.selectedObject.id,
object: zoneEditorStore.selectedObject, object: mapEditorStore.selectedObject,
depth: 0, depth: 0,
isRotated: false, isRotated: false,
positionX: tile.x, positionX: tile.x,
positionY: tile.y positionY: tile.y
} }
// Add new object to zoneObjects // Add new object to mapObjects
zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.concat(newObject as ZoneObjectT) mapEditorStore.map.mapObjects = mapEditorStore.map.mapObjects.concat(newObject as MapObjectT)
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is eraser // Check if tool is eraser
if (zoneEditorStore.tool !== 'eraser') return if (mapEditorStore.tool !== 'eraser') return
// Check if draw mode is object // Check if draw mode is object
if (zoneEditorStore.eraserMode !== 'object') return if (mapEditorStore.eraserMode !== 'object') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -92,22 +92,22 @@ function eraser(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingObject = zoneEditorStore.zone.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y) const existingObject = mapEditorStore.map.mapObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
if (!existingObject) return if (!existingObject) return
// Remove existing object // Remove existing object
zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== existingObject.id) mapEditorStore.map.mapObjects = mapEditorStore.map.mapObjects.filter((object) => object.id !== existingObject.id)
} }
function objectPicker(pointer: Phaser.Input.Pointer) { function objectPicker(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is object // Check if draw mode is object
if (zoneEditorStore.drawMode !== 'object') return if (mapEditorStore.drawMode !== 'object') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -123,44 +123,44 @@ function objectPicker(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Check if object already exists on position // Check if object already exists on position
const existingObject = zoneEditorStore.zone.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y) const existingObject = mapEditorStore.map.mapObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
if (!existingObject) return if (!existingObject) return
// Select the object // Select the object
zoneEditorStore.setSelectedObject(existingObject) mapEditorStore.setSelectedObject(existingObject)
} }
function moveZoneObject(id: string) { function moveMapObject(id: string) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
movingZoneObject.value = zoneEditorStore.zone.zoneObjects.find((object) => object.id === id) as ZoneObjectT movingMapObject.value = mapEditorStore.map.mapObjects.find((object) => object.id === id) as MapObjectT
function handlePointerMove(pointer: Phaser.Input.Pointer) { function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (!movingZoneObject.value) return if (!movingMapObject.value) return
const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY) const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
movingZoneObject.value.positionX = tile.x movingMapObject.value.positionX = tile.x
movingZoneObject.value.positionY = tile.y movingMapObject.value.positionY = tile.y
} }
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
function handlePointerUp() { function handlePointerUp() {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
movingZoneObject.value = null movingMapObject.value = null
} }
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp) scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
} }
function rotateZoneObject(id: string) { function rotateMapObject(id: string) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.map((object) => { mapEditorStore.map.mapObjects = mapEditorStore.map.mapObjects.map((object) => {
if (object.id === id) { if (object.id === id) {
return { return {
...object, ...object,
@ -171,20 +171,20 @@ function rotateZoneObject(id: string) {
}) })
} }
function deleteZoneObject(id: string) { function deleteMapObject(id: string) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== id) mapEditorStore.map.mapObjects = mapEditorStore.map.mapObjects.filter((object) => object.id !== id)
selectedZoneObject.value = null selectedMapObject.value = null
} }
function clickZoneObject(zoneObject: ZoneObjectT) { function clickMapObject(mapObject: MapObjectT) {
selectedZoneObject.value = zoneObject selectedMapObject.value = mapObject
// If alt is pressed, select the object // If alt is pressed, select the object
if (scene.input.activePointer.event.altKey) { if (scene.input.activePointer.event.altKey) {
zoneEditorStore.setSelectedObject(zoneObject.object) mapEditorStore.setSelectedObject(mapObject.object)
} }
} }
@ -204,39 +204,39 @@ onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker) scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker)
}) })
// watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects // watch mapEditorStore.objectList and update originX and originY of objects in mapObjects
watch( watch(
() => zoneEditorStore.objectList, () => mapEditorStore.objectList,
(newObjects) => { (newObjects) => {
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
const updatedZoneObjects = zoneEditorStore.zone.zoneObjects.map((zoneObject) => { const updatedMapObjects = mapEditorStore.map.mapObjects.map((mapObject) => {
const updatedObject = newObjects.find((obj) => obj.id === zoneObject.object.id) const updatedObject = newObjects.find((obj) => obj.id === mapObject.object.id)
if (updatedObject) { if (updatedObject) {
return { return {
...zoneObject, ...mapObject,
object: { object: {
...zoneObject.object, ...mapObject.object,
originX: updatedObject.originX, originX: updatedObject.originX,
originY: updatedObject.originY originY: updatedObject.originY
} }
} }
} }
return zoneObject return mapObject
}) })
// Update the zone with the new zoneObjects // Update the map with the new mapObjects
zoneEditorStore.setZone({ mapEditorStore.setMap({
...zoneEditorStore.zone, ...mapEditorStore.map,
zoneObjects: updatedZoneObjects mapObjects: updatedMapObjects
}) })
// Update selectedObject if it's set // Update selectedObject if it's set
if (zoneEditorStore.selectedObject) { if (mapEditorStore.selectedObject) {
const updatedObject = newObjects.find((obj) => obj.id === zoneEditorStore.selectedObject?.id) const updatedObject = newObjects.find((obj) => obj.id === mapEditorStore.selectedObject?.id)
if (updatedObject) { if (updatedObject) {
zoneEditorStore.setSelectedObject({ mapEditorStore.setSelectedObject({
...zoneEditorStore.selectedObject, ...mapEditorStore.selectedObject,
originX: updatedObject.originX, originX: updatedObject.originX,
originY: updatedObject.originY originY: updatedObject.originY
}) })

View File

@ -6,9 +6,9 @@
import config from '@/application/config' import config from '@/application/config'
import type { AssetDataT } from '@/application/types' import type { AssetDataT } from '@/application/types'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { createTileArray, getTile, placeTile, setLayerTiles } from '@/composables/zoneComposable' import { createTileArray, getTile, placeTile, setLayerTiles } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onMounted, onUnmounted, watch } from 'vue' import { onMounted, onUnmounted, watch } from 'vue'
@ -16,7 +16,7 @@ const emit = defineEmits(['tileMap:create'])
const scene = useScene() const scene = useScene()
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const tileMap = createTileMap() const tileMap = createTileMap()
const tileLayer = createTileLayer() const tileLayer = createTileLayer()
@ -26,16 +26,16 @@ const tileLayer = createTileLayer()
* A map can have one or more tilemap layers, which are the display objects that actually render the tiles. * A map can have one or more tilemap layers, which are the display objects that actually render the tiles.
*/ */
function createTileMap() { function createTileMap() {
const zoneData = new Phaser.Tilemaps.MapData({ const mapData = new Phaser.Tilemaps.MapData({
width: zoneEditorStore.zone?.width, width: mapEditorStore.map?.width,
height: zoneEditorStore.zone?.height, height: mapEditorStore.map?.height,
tileWidth: config.tile_size.x, tileWidth: config.tile_size.x,
tileHeight: config.tile_size.y, tileHeight: config.tile_size.y,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC, orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D format: Phaser.Tilemaps.Formats.ARRAY_2D
}) })
const newTileMap = new Phaser.Tilemaps.Tilemap(scene, zoneData) const newTileMap = new Phaser.Tilemaps.Tilemap(scene, mapData)
emit('tileMap:create', newTileMap) emit('tileMap:create', newTileMap)
return newTileMap return newTileMap
@ -62,17 +62,17 @@ function createTileLayer() {
} }
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is tile // Check if draw mode is tile
if (zoneEditorStore.drawMode !== 'tile') return if (mapEditorStore.drawMode !== 'tile') return
// Check if there is a selected tile // Check if there is a selected tile
if (!zoneEditorStore.selectedTile) return if (!mapEditorStore.selectedTile) return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -85,21 +85,21 @@ function pencil(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(tileMap, tileLayer, tile.x, tile.y, zoneEditorStore.selectedTile) placeTile(tileMap, tileLayer, tile.x, tile.y, mapEditorStore.selectedTile)
// Adjust zoneEditorStore.zone.tiles // Adjust mapEditorStore.map.tiles
zoneEditorStore.zone.tiles[tile.y][tile.x] = zoneEditorStore.selectedTile mapEditorStore.map.tiles[tile.y][tile.x] = mapEditorStore.selectedTile
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'eraser') return if (mapEditorStore.tool !== 'eraser') return
// Check if draw mode is tile // Check if draw mode is tile
if (zoneEditorStore.eraserMode !== 'tile') return if (mapEditorStore.eraserMode !== 'tile') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -117,19 +117,19 @@ function eraser(pointer: Phaser.Input.Pointer) {
// Place tile // Place tile
placeTile(tileMap, tileLayer, tile.x, tile.y, 'blank_tile') placeTile(tileMap, tileLayer, tile.x, tile.y, 'blank_tile')
// Adjust zoneEditorStore.zone.tiles // Adjust mapEditorStore.map.tiles
zoneEditorStore.zone.tiles[tile.y][tile.x] = 'blank_tile' mapEditorStore.map.tiles[tile.y][tile.x] = 'blank_tile'
} }
function paint(pointer: Phaser.Input.Pointer) { function paint(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'paint') return if (mapEditorStore.tool !== 'paint') return
// Check if there is a selected tile // Check if there is a selected tile
if (!zoneEditorStore.selectedTile) return if (!mapEditorStore.selectedTile) return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -141,22 +141,22 @@ function paint(pointer: Phaser.Input.Pointer) {
if (pointer.event.altKey) return if (pointer.event.altKey) return
// Set new tileArray with selected tile // Set new tileArray with selected tile
setLayerTiles(tileMap, tileLayer, createTileArray(tileMap.width, tileMap.height, zoneEditorStore.selectedTile)) setLayerTiles(tileMap, tileLayer, createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile))
// Adjust zoneEditorStore.zone.tiles // Adjust mapEditorStore.map.tiles
zoneEditorStore.zone.tiles = createTileArray(tileMap.width, tileMap.height, zoneEditorStore.selectedTile) mapEditorStore.map.tiles = createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile)
} }
// When alt is pressed, and the pointer is down, select the tile that the pointer is over // When alt is pressed, and the pointer is down, select the tile that the pointer is over
function tilePicker(pointer: Phaser.Input.Pointer) { function tilePicker(pointer: Phaser.Input.Pointer) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// Check if tool is pencil // Check if tool is pencil
if (zoneEditorStore.tool !== 'pencil') return if (mapEditorStore.tool !== 'pencil') return
// Check if draw mode is tile // Check if draw mode is tile
if (zoneEditorStore.drawMode !== 'tile') return if (mapEditorStore.drawMode !== 'tile') return
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
@ -172,36 +172,36 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
if (!tile) return if (!tile) return
// Select the tile // Select the tile
zoneEditorStore.setSelectedTile(zoneEditorStore.zone.tiles[tile.y][tile.x]) mapEditorStore.setSelectedTile(mapEditorStore.map.tiles[tile.y][tile.x])
} }
watch( watch(
() => zoneEditorStore.shouldClearTiles, () => mapEditorStore.shouldClearTiles,
(shouldClear) => { (shouldClear) => {
if (shouldClear && zoneEditorStore.zone) { if (shouldClear && mapEditorStore.map) {
const blankTiles = createTileArray(tileMap.width, tileMap.height, 'blank_tile') const blankTiles = createTileArray(tileMap.width, tileMap.height, 'blank_tile')
setLayerTiles(tileMap, tileLayer, blankTiles) setLayerTiles(tileMap, tileLayer, blankTiles)
zoneEditorStore.zone.tiles = blankTiles mapEditorStore.map.tiles = blankTiles
zoneEditorStore.resetClearTilesFlag() mapEditorStore.resetClearTilesFlag()
} }
} }
) )
onMounted(() => { onMounted(() => {
if (!zoneEditorStore.zone?.tiles) { if (!mapEditorStore.map?.tiles) {
return return
} }
// First fill the entire map with blank tiles using current zone dimensions // First fill the entire map with blank tiles using current map dimensions
const blankTiles = createTileArray(zoneEditorStore.zone.width, zoneEditorStore.zone.height, 'blank_tile') const blankTiles = createTileArray(mapEditorStore.map.width, mapEditorStore.map.height, 'blank_tile')
// Then overlay the zone tiles, but only within the current zone dimensions // Then overlay the map tiles, but only within the current map dimensions
const zoneTiles = zoneEditorStore.zone.tiles const mapTiles = mapEditorStore.map.tiles
for (let y = 0; y < zoneEditorStore.zone.height; y++) { for (let y = 0; y < mapEditorStore.map.height; y++) {
for (let x = 0; x < zoneEditorStore.zone.width; x++) { for (let x = 0; x < mapEditorStore.map.width; x++) {
// Only copy if the source tiles array has this position // Only copy if the source tiles array has this position
if (zoneTiles[y] && zoneTiles[y][x] !== undefined) { if (mapTiles[y] && mapTiles[y][x] !== undefined) {
blankTiles[y][x] = zoneTiles[y][x] blankTiles[y][x] = mapTiles[y][x]
} }
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<Modal :isModalOpen="true" @modal:close="() => zoneEditorStore.toggleCreateZoneModal()" :modal-width="300" :modal-height="420" :is-resizable="false" :bg-style="'none'"> <Modal :isModalOpen="true" @modal:close="() => mapEditorStore.toggleCreateMapModal()" :modal-width="300" :modal-height="420" :is-resizable="false" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Create new zone</h3> <h3 class="m-0 font-medium shrink-0 text-white">Create new map</h3>
</template> </template>
<template #modalBody> <template #modalBody>
@ -36,23 +36,23 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Zone } from '@/application/types' import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { ref } from 'vue' import { ref } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const name = ref('') const name = ref('')
const width = ref(0) const width = ref(0)
const height = ref(0) const height = ref(0)
function submit() { function submit() {
gameStore.connection.emit('gm:zone_editor:zone:create', { name: name.value, width: width.value, height: height.value }, (response: Zone[]) => { gameStore.connection.emit('gm:map_editor:map:create', { name: name.value, width: width.value, height: height.value }, (response: Map[]) => {
zoneEditorStore.setZoneList(response) mapEditorStore.setMapList(response)
}) })
zoneEditorStore.toggleCreateZoneModal() mapEditorStore.toggleCreateMapModal()
} }
</script> </script>

View File

@ -0,0 +1,61 @@
<template>
<CreateMap v-if="mapEditorStore.isCreateMapModalShown" />
<Modal :is-modal-open="mapEditorStore.isMapListModalShown" @modal:close="() => mapEditorStore.toggleMapListModal()" :is-resizable="false" :modal-width="300" :modal-height="360" :bg-style="'none'">
<template #modalHeader>
<h3 class="text-lg text-white">Maps</h3>
</template>
<template #modalBody>
<div class="my-4 mx-auto">
<div class="text-center mb-4 px-2 flex gap-2.5">
<button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="fetchMaps">Refresh</button>
<button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => mapEditorStore.toggleCreateMapModal()">New</button>
</div>
<div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(map, index) in mapEditorStore.mapList" :key="map.id">
<div class="absolute left-0 top-0 w-full h-px bg-gray-500" v-if="index === 0"></div>
<div class="flex gap-3 items-center w-full" @click="() => loadMap(map.id)">
<span>{{ map.name }}</span>
<span class="ml-auto gap-1 flex">
<button class="btn-red w-7 h-7 z-50 flex items-center justify-center" @click.stop="() => deleteMap(map.id)">x</button>
</span>
</div>
<div class="absolute left-0 bottom-0 w-full h-px bg-gray-500"></div>
</div>
</div>
</template>
</Modal>
</template>
<script setup lang="ts">
import type { Map } from '@/application/types'
import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue'
import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onMounted } from 'vue'
const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore()
onMounted(async () => {
fetchMaps()
})
function fetchMaps() {
gameStore.connection?.emit('gm:map_editor:map:list', {}, (response: Map[]) => {
mapEditorStore.setMapList(response)
})
}
function loadMap(id: number) {
gameStore.connection?.emit('gm:map_editor:map:request', { mapId: id }, (response: Map) => {
mapEditorStore.setMap(response)
})
mapEditorStore.toggleMapListModal()
}
function deleteMap(id: number) {
gameStore.connection?.emit('gm:map_editor:map:delete', { mapId: id }, () => {
fetchMaps()
})
}
</script>

View File

@ -1,7 +1,7 @@
<template> <template>
<Modal :is-modal-open="zoneEditorStore.isSettingsModalShown" @modal:close="() => zoneEditorStore.toggleSettingsModal()" :modal-width="600" :modal-height="430" :bg-style="'none'"> <Modal :is-modal-open="mapEditorStore.isSettingsModalShown" @modal:close="() => mapEditorStore.toggleSettingsModal()" :modal-width="600" :modal-height="430" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Zone settings</h3> <h3 class="m-0 font-medium shrink-0 text-white">Map settings</h3>
</template> </template>
<template #modalBody> <template #modalBody>
@ -34,7 +34,7 @@
</div> </div>
</form> </form>
<form method="post" @submit.prevent="" class="inline" v-if="screen === 'effects'"> <form method="post" @submit.prevent="" class="inline" v-if="screen === 'effects'">
<div v-for="(effect, index) in zoneEffects" :key="effect.id" class="mb-2 flex items-center space-x-2 mt-4"> <div v-for="(effect, index) in mapEffects" :key="effect.id" class="mb-2 flex items-center space-x-2 mt-4">
<input class="input-field flex-grow" v-model="effect.effect" placeholder="Effect name" /> <input class="input-field flex-grow" v-model="effect.effect" placeholder="Effect name" />
<input class="input-field w-20" v-model.number="effect.strength" type="number" placeholder="Strength" /> <input class="input-field w-20" v-model.number="effect.strength" type="number" placeholder="Strength" />
<button class="btn-red py-1 px-2" type="button" @click="removeEffect(index)">Delete</button> <button class="btn-red py-1 px-2" type="button" @click="removeEffect(index)">Delete</button>
@ -48,59 +48,59 @@
<script setup> <script setup>
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const screen = ref('settings') const screen = ref('settings')
zoneEditorStore.setZoneName(zoneEditorStore.zone?.name) mapEditorStore.setMapName(mapEditorStore.map?.name)
zoneEditorStore.setZoneWidth(zoneEditorStore.zone?.width) mapEditorStore.setMapWidth(mapEditorStore.map?.width)
zoneEditorStore.setZoneHeight(zoneEditorStore.zone?.height) mapEditorStore.setMapHeight(mapEditorStore.map?.height)
zoneEditorStore.setZonePvp(zoneEditorStore.zone?.pvp) mapEditorStore.setMapPvp(mapEditorStore.map?.pvp)
zoneEditorStore.setZoneEffects(zoneEditorStore.zone?.zoneEffects) mapEditorStore.setMapEffects(mapEditorStore.map?.mapEffects)
const name = ref(zoneEditorStore.zoneSettings?.name) const name = ref(mapEditorStore.mapSettings?.name)
const width = ref(zoneEditorStore.zoneSettings?.width) const width = ref(mapEditorStore.mapSettings?.width)
const height = ref(zoneEditorStore.zoneSettings?.height) const height = ref(mapEditorStore.mapSettings?.height)
const pvp = ref(zoneEditorStore.zoneSettings?.pvp) const pvp = ref(mapEditorStore.mapSettings?.pvp)
const zoneEffects = ref(zoneEditorStore.zoneSettings?.zoneEffects || []) const mapEffects = ref(mapEditorStore.mapSettings?.mapEffects || [])
watch(name, (value) => { watch(name, (value) => {
zoneEditorStore.setZoneName(value) mapEditorStore.setMapName(value)
}) })
watch(width, (value) => { watch(width, (value) => {
zoneEditorStore.setZoneWidth(value) mapEditorStore.setMapWidth(value)
}) })
watch(height, (value) => { watch(height, (value) => {
zoneEditorStore.setZoneHeight(value) mapEditorStore.setMapHeight(value)
}) })
watch(pvp, (value) => { watch(pvp, (value) => {
zoneEditorStore.setZonePvp(value) mapEditorStore.setMapPvp(value)
}) })
watch( watch(
zoneEffects, mapEffects,
(value) => { (value) => {
zoneEditorStore.setZoneEffects(value) mapEditorStore.setMapEffects(value)
}, },
{ deep: true } { deep: true }
) )
const addEffect = () => { const addEffect = () => {
zoneEffects.value.push({ mapEffects.value.push({
id: Date.now().toString(), // Simple unique id generation id: Date.now().toString(), // Simple unique id generation
zoneId: zoneEditorStore.zone?.id, mapId: mapEditorStore.map?.id,
zone: zoneEditorStore.zone, map: mapEditorStore.map,
effect: '', effect: '',
strength: 1 strength: 1
}) })
} }
const removeEffect = (index) => { const removeEffect = (index) => {
zoneEffects.value.splice(index, 1) mapEffects.value.splice(index, 1)
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="zoneEditorStore.isObjectListModalShown" :modal-width="645" :modal-height="260" @modal:close="() => (zoneEditorStore.isObjectListModalShown = false)" :bg-style="'none'"> <Modal :isModalOpen="mapEditorStore.isObjectListModalShown" :modal-width="645" :modal-height="260" @modal:close="() => (mapEditorStore.isObjectListModalShown = false)" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="text-lg text-white">Objects</h3> <h3 class="text-lg text-white">Objects</h3>
</template> </template>
@ -25,11 +25,11 @@
class="border-2 border-solid max-w-full" class="border-2 border-solid max-w-full"
:src="`${config.server_endpoint}/assets/objects/${object.id}.png`" :src="`${config.server_endpoint}/assets/objects/${object.id}.png`"
alt="Object" alt="Object"
@click="zoneEditorStore.setSelectedObject(object)" @click="mapEditorStore.setSelectedObject(object)"
:class="{ :class="{
'cursor-pointer transition-all duration-300': true, 'cursor-pointer transition-all duration-300': true,
'border-cyan shadow-lg scale-105': zoneEditorStore.selectedObject?.id === object.id, 'border-cyan shadow-lg scale-105': mapEditorStore.selectedObject?.id === object.id,
'border-transparent hover:border-gray-300': zoneEditorStore.selectedObject?.id !== object.id 'border-transparent hover:border-gray-300': mapEditorStore.selectedObject?.id !== object.id
}" }"
/> />
</div> </div>
@ -42,25 +42,25 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import type { Object, ZoneObject } from '@/application/types' import type { Object, PlacedMapObject } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const isModalOpen = ref(false) const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const searchQuery = ref('') const searchQuery = ref('')
const selectedTags = ref<string[]>([]) const selectedTags = ref<string[]>([])
const uniqueTags = computed(() => { const uniqueTags = computed(() => {
const allTags = zoneEditorStore.objectList.flatMap((obj) => obj.tags || []) const allTags = mapEditorStore.objectList.flatMap((obj) => obj.tags || [])
return Array.from(new Set(allTags)) return Array.from(new Set(allTags))
}) })
const filteredObjects = computed(() => { const filteredObjects = computed(() => {
return zoneEditorStore.objectList.filter((object) => { return mapEditorStore.objectList.filter((object) => {
const matchesSearch = !searchQuery.value || object.name.toLowerCase().includes(searchQuery.value.toLowerCase()) const matchesSearch = !searchQuery.value || object.name.toLowerCase().includes(searchQuery.value.toLowerCase())
const matchesTags = selectedTags.value.length === 0 || (object.tags && selectedTags.value.some((tag) => object.tags.includes(tag))) const matchesTags = selectedTags.value.length === 0 || (object.tags && selectedTags.value.some((tag) => object.tags.includes(tag)))
return matchesSearch && matchesTags return matchesSearch && matchesTags
@ -78,7 +78,7 @@ const toggleTag = (tag: string) => {
onMounted(async () => { onMounted(async () => {
isModalOpen.value = true isModalOpen.value = true
gameStore.connection?.emit('gm:object:list', {}, (response: Object[]) => { gameStore.connection?.emit('gm:object:list', {}, (response: Object[]) => {
zoneEditorStore.setObjectList(response) mapEditorStore.setObjectList(response)
}) })
}) })
</script> </script>

View File

@ -11,23 +11,23 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ZoneObject } from '@/application/types' import type { PlacedMapObject } from '@/application/types'
const props = defineProps<{ const props = defineProps<{
zoneObject: ZoneObject mapObject: PlacedMapObject
}>() }>()
const emit = defineEmits(['move', 'rotate', 'delete']) const emit = defineEmits(['move', 'rotate', 'delete'])
const handleMove = () => { const handleMove = () => {
emit('move', props.zoneObject.id) emit('move', props.mapObject.id)
} }
const handleRotate = () => { const handleRotate = () => {
emit('rotate', props.zoneObject.id) emit('rotate', props.mapObject.id)
} }
const handleDelete = () => { const handleDelete = () => {
emit('delete', props.zoneObject.id) emit('delete', props.mapObject.id)
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :is-modal-open="showTeleportModal" @modal:close="() => zoneEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" :bg-style="'none'"> <Modal :is-modal-open="showTeleportModal" @modal:close="() => mapEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3> <h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3>
</template> </template>
@ -25,10 +25,10 @@
</select> </select>
</div> </div>
<div class="form-field-full"> <div class="form-field-full">
<label for="toZoneId">Zone to teleport to</label> <label for="toMapId">Map to teleport to</label>
<select v-model="toZoneId" class="input-field" name="toZoneId" id="toZoneId"> <select v-model="toMapId" class="input-field" name="toMapId" id="toMapId">
<option :value="0">Select zone</option> <option :value="0">Select map</option>
<option v-for="zone in zoneEditorStore.zoneList" :key="zone.id" :value="zone.id">{{ zone.name }}</option> <option v-for="map in mapEditorStore.mapList" :key="map.id" :value="map.id">{{ map.name }}</option>
</select> </select>
</div> </div>
</div> </div>
@ -39,44 +39,44 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Zone } from '@/application/types' import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
const showTeleportModal = computed(() => zoneEditorStore.tool === 'pencil' && zoneEditorStore.drawMode === 'teleport') const showTeleportModal = computed(() => mapEditorStore.tool === 'pencil' && mapEditorStore.drawMode === 'teleport')
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const gameStore = useGameStore() const gameStore = useGameStore()
onMounted(fetchZones) onMounted(fetchMaps)
function fetchZones() { function fetchMaps() {
gameStore.connection?.emit('gm:zone_editor:zone:list', {}, (response: Zone[]) => { gameStore.connection?.emit('gm:map_editor:map:list', {}, (response: Map[]) => {
zoneEditorStore.setZoneList(response) mapEditorStore.setMapList(response)
}) })
} }
const { toPositionX, toPositionY, toRotation, toZoneId } = useRefTeleportSettings() const { toPositionX, toPositionY, toRotation, toMapId } = useRefTeleportSettings()
function useRefTeleportSettings() { function useRefTeleportSettings() {
const settings = zoneEditorStore.teleportSettings const settings = mapEditorStore.teleportSettings
return { return {
toPositionX: ref(settings.toPositionX), toPositionX: ref(settings.toPositionX),
toPositionY: ref(settings.toPositionY), toPositionY: ref(settings.toPositionY),
toRotation: ref(settings.toRotation), toRotation: ref(settings.toRotation),
toZoneId: ref(settings.toZoneId) toMapId: ref(settings.toMapId)
} }
} }
watch([toPositionX, toPositionY, toRotation, toZoneId], updateTeleportSettings) watch([toPositionX, toPositionY, toRotation, toMapId], updateTeleportSettings)
function updateTeleportSettings() { function updateTeleportSettings() {
zoneEditorStore.setTeleportSettings({ mapEditorStore.setTeleportSettings({
toPositionX: toPositionX.value, toPositionX: toPositionX.value,
toPositionY: toPositionY.value, toPositionY: toPositionY.value,
toRotation: toRotation.value, toRotation: toRotation.value,
toZoneId: toZoneId.value toMapId: toMapId.value
}) })
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="zoneEditorStore.isTileListModalShown" :modal-width="645" :modal-height="600" @modal:close="() => (zoneEditorStore.isTileListModalShown = false)" :bg-style="'none'"> <Modal :isModalOpen="mapEditorStore.isTileListModalShown" :modal-width="645" :modal-height="600" @modal:close="() => (mapEditorStore.isTileListModalShown = false)" :bg-style="'none'">
<template #modalHeader> <template #modalHeader>
<h3 class="text-lg text-white">Tiles</h3> <h3 class="text-lg text-white">Tiles</h3>
</template> </template>
@ -85,25 +85,25 @@ import config from '@/application/config'
import type { Tile } from '@/application/types' import type { Tile } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const isModalOpen = ref(false) const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const searchQuery = ref('') const searchQuery = ref('')
const selectedTags = ref<string[]>([]) const selectedTags = ref<string[]>([])
const tileCategories = ref<Map<string, string>>(new Map()) const tileCategories = ref<Map<string, string>>(new Map())
const selectedGroup = ref<{ parent: Tile; children: Tile[] } | null>(null) const selectedGroup = ref<{ parent: Tile; children: Tile[] } | null>(null)
const uniqueTags = computed(() => { const uniqueTags = computed(() => {
const allTags = zoneEditorStore.tileList.flatMap((tile) => tile.tags || []) const allTags = mapEditorStore.tileList.flatMap((tile) => tile.tags || [])
return Array.from(new Set(allTags)) return Array.from(new Set(allTags))
}) })
const groupedTiles = computed(() => { const groupedTiles = computed(() => {
const groups: { parent: Tile; children: Tile[] }[] = [] const groups: { parent: Tile; children: Tile[] }[] = []
const filteredTiles = zoneEditorStore.tileList.filter((tile) => { const filteredTiles = mapEditorStore.tileList.filter((tile) => {
const matchesSearch = !searchQuery.value || tile.name.toLowerCase().includes(searchQuery.value.toLowerCase()) const matchesSearch = !searchQuery.value || tile.name.toLowerCase().includes(searchQuery.value.toLowerCase())
const matchesTags = selectedTags.value.length === 0 || (tile.tags && selectedTags.value.some((tag) => tile.tags.includes(tag))) const matchesTags = selectedTags.value.length === 0 || (tile.tags && selectedTags.value.some((tag) => tile.tags.includes(tag)))
return matchesSearch && matchesTags return matchesSearch && matchesTags
@ -219,17 +219,17 @@ function closeGroup() {
} }
function selectTile(tile: string) { function selectTile(tile: string) {
zoneEditorStore.setSelectedTile(tile) mapEditorStore.setSelectedTile(tile)
} }
function isActiveTile(tile: Tile): boolean { function isActiveTile(tile: Tile): boolean {
return zoneEditorStore.selectedTile === tile.id return mapEditorStore.selectedTile === tile.id
} }
onMounted(async () => { onMounted(async () => {
isModalOpen.value = true isModalOpen.value = true
gameStore.connection?.emit('gm:tile:list', {}, (response: Tile[]) => { gameStore.connection?.emit('gm:tile:list', {}, (response: Tile[]) => {
zoneEditorStore.setTileList(response) mapEditorStore.setTileList(response)
response.forEach((tile) => processTile(tile)) response.forEach((tile) => processTile(tile))
}) })
}) })

View File

@ -1,21 +1,21 @@
<template> <template>
<div class="flex justify-center p-5"> <div class="flex justify-center p-5">
<div class="toolbar fixed bottom-0 left-0 m-3 rounded flex bg-gray solid border-solid border-2 border-gray-500 text-gray-300 p-1.5 px-3 h-10"> <div class="toolbar fixed bottom-0 left-0 m-3 rounded flex bg-gray solid border-solid border-2 border-gray-500 text-gray-300 p-1.5 px-3 h-10">
<div ref="toolbar" class="tools flex gap-2.5" v-if="zoneEditorStore.zone"> <div ref="toolbar" class="tools flex gap-2.5" v-if="mapEditorStore.map">
<button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': zoneEditorStore.tool === 'move' }" @click="handleClick('move')"> <button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': mapEditorStore.tool === 'move' }" @click="handleClick('move')">
<img class="invert w-5 h-5" src="/assets/icons/zoneEditor/move.svg" alt="Move camera" /> <span class="h-5" :class="{ 'ml-2.5': zoneEditorStore.tool !== 'move' }">(M)</span> <img class="invert w-5 h-5" src="/assets/icons/mapEditor/move.svg" alt="Move camera" /> <span class="h-5" :class="{ 'ml-2.5': mapEditorStore.tool !== 'move' }">(M)</span>
</button> </button>
<div class="w-px bg-cyan"></div> <div class="w-px bg-cyan"></div>
<button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': zoneEditorStore.tool === 'pencil' }" @click="handleClick('pencil')"> <button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': mapEditorStore.tool === 'pencil' }" @click="handleClick('pencil')">
<img class="invert w-5 h-5" src="/assets/icons/zoneEditor/pencil.svg" alt="Pencil" /> <span class="h-5" :class="{ 'ml-2.5': zoneEditorStore.tool !== 'pencil' }">(P)</span> <img class="invert w-5 h-5" src="/assets/icons/mapEditor/pencil.svg" alt="Pencil" /> <span class="h-5" :class="{ 'ml-2.5': mapEditorStore.tool !== 'pencil' }">(P)</span>
<div class="select" v-if="zoneEditorStore.tool === 'pencil'"> <div class="select" v-if="mapEditorStore.tool === 'pencil'">
<div class="select-trigger group capitalize flex gap-3.5" :class="{ open: selectPencilOpen }"> <div class="select-trigger group capitalize flex gap-3.5" :class="{ open: selectPencilOpen }">
{{ zoneEditorStore.drawMode }} {{ mapEditorStore.drawMode }}
<img class="group-[.open]:rotate-180 invert w-5 h-5 rotate-0 transition ease-in-out duration-200" src="/assets/icons/zoneEditor/chevron.svg" /> <img class="group-[.open]:rotate-180 invert w-5 h-5 rotate-0 transition ease-in-out duration-200" src="/assets/icons/mapEditor/chevron.svg" />
</div> </div>
<div class="flex flex-col absolute bottom-full mb-5 left-1/2 -translate-x-1/2 bg-gray rounded min-w-28 border border-gray-500 border-solid text-left" v-show="selectPencilOpen && zoneEditorStore.tool === 'pencil'"> <div class="flex flex-col absolute bottom-full mb-5 left-1/2 -translate-x-1/2 bg-gray rounded min-w-28 border border-gray-500 border-solid text-left" v-show="selectPencilOpen && mapEditorStore.tool === 'pencil'">
<span class="py-2 px-2.5 relative hover:bg-cyan hover:text-white" @click="setDrawMode('tile')"> <span class="py-2 px-2.5 relative hover:bg-cyan hover:text-white" @click="setDrawMode('tile')">
Tile Tile
<div class="absolute w-4/5 left-1/2 -translate-x-1/2 bottom-0 h-px bg-cyan"></div> <div class="absolute w-4/5 left-1/2 -translate-x-1/2 bottom-0 h-px bg-cyan"></div>
@ -35,12 +35,12 @@
<div class="w-px bg-cyan"></div> <div class="w-px bg-cyan"></div>
<button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': zoneEditorStore.tool === 'eraser' }" @click="handleClick('eraser')"> <button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': mapEditorStore.tool === 'eraser' }" @click="handleClick('eraser')">
<img class="invert w-5 h-5" src="/assets/icons/zoneEditor/eraser.svg" alt="Eraser" /> <span class="h-5" :class="{ 'ml-2.5': zoneEditorStore.tool !== 'eraser' }">(E)</span> <img class="invert w-5 h-5" src="/assets/icons/mapEditor/eraser.svg" alt="Eraser" /> <span class="h-5" :class="{ 'ml-2.5': mapEditorStore.tool !== 'eraser' }">(E)</span>
<div class="select" v-if="zoneEditorStore.tool === 'eraser'"> <div class="select" v-if="mapEditorStore.tool === 'eraser'">
<div class="select-trigger group capitalize flex gap-3.5" :class="{ open: selectEraserOpen }"> <div class="select-trigger group capitalize flex gap-3.5" :class="{ open: selectEraserOpen }">
{{ zoneEditorStore.eraserMode }} {{ mapEditorStore.eraserMode }}
<img class="group-[.open]:rotate-180 invert w-5 h-5 rotate-0 transition ease-in-out duration-200" src="/assets/icons/zoneEditor/chevron.svg" /> <img class="group-[.open]:rotate-180 invert w-5 h-5 rotate-0 transition ease-in-out duration-200" src="/assets/icons/mapEditor/chevron.svg" />
</div> </div>
<div class="flex flex-col absolute bottom-full mb-5 left-1/2 -translate-x-1/2 bg-gray rounded min-w-28 border border-gray-500 border-solid text-left" v-show="selectEraserOpen"> <div class="flex flex-col absolute bottom-full mb-5 left-1/2 -translate-x-1/2 bg-gray rounded min-w-28 border border-gray-500 border-solid text-left" v-show="selectEraserOpen">
<span class="py-2 px-2.5 relative hover:bg-cyan hover:text-white" @click="setEraserMode('tile')"> <span class="py-2 px-2.5 relative hover:bg-cyan hover:text-white" @click="setEraserMode('tile')">
@ -62,31 +62,31 @@
<div class="w-px bg-cyan"></div> <div class="w-px bg-cyan"></div>
<button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': zoneEditorStore.tool === 'paint' }" @click="handleClick('paint')"> <button class="flex justify-center items-center min-w-10 p-0 relative" :class="{ 'border-0 border-b-[3px] border-solid border-cyan gap-2.5': mapEditorStore.tool === 'paint' }" @click="handleClick('paint')">
<img class="invert w-5 h-5" src="/assets/icons/zoneEditor/paint.svg" alt="Paint bucket" /> <span class="h-5" :class="{ 'ml-2.5': zoneEditorStore.tool !== 'paint' }">(B)</span> <img class="invert w-5 h-5" src="/assets/icons/mapEditor/paint.svg" alt="Paint bucket" /> <span class="h-5" :class="{ 'ml-2.5': mapEditorStore.tool !== 'paint' }">(B)</span>
</button> </button>
<div class="w-px bg-cyan"></div> <div class="w-px bg-cyan"></div>
<button class="flex justify-center items-center min-w-10 p-0 relative" @click="handleClick('settings')" v-if="zoneEditorStore.zone"><img class="invert w-5 h-5" src="/assets/icons/zoneEditor/gear.svg" alt="Zone settings" /> <span class="h-5 ml-2.5">(Z)</span></button> <button class="flex justify-center items-center min-w-10 p-0 relative" @click="handleClick('settings')" v-if="mapEditorStore.map"><img class="invert w-5 h-5" src="/assets/icons/mapEditor/gear.svg" alt="Map settings" /> <span class="h-5 ml-2.5">(Z)</span></button>
</div> </div>
<div class="toolbar fixed bottom-0 right-0 m-3 rounded flex bg-gray solid border-solid border-2 border-gray-500 text-gray-300 p-1.5 px-3 h-10 space-x-2"> <div class="toolbar fixed bottom-0 right-0 m-3 rounded flex bg-gray solid border-solid border-2 border-gray-500 text-gray-300 p-1.5 px-3 h-10 space-x-2">
<button class="btn-cyan px-3.5" @click="() => zoneEditorStore.toggleZoneListModal()">Load</button> <button class="btn-cyan px-3.5" @click="() => mapEditorStore.toggleMapListModal()">Load</button>
<button class="btn-cyan px-3.5" @click="() => emit('save')" v-if="zoneEditorStore.zone">Save</button> <button class="btn-cyan px-3.5" @click="() => emit('save')" v-if="mapEditorStore.map">Save</button>
<button class="btn-cyan px-3.5" @click="() => emit('clear')" v-if="zoneEditorStore.zone">Clear</button> <button class="btn-cyan px-3.5" @click="() => emit('clear')" v-if="mapEditorStore.map">Clear</button>
<button class="btn-cyan px-3.5" @click="() => zoneEditorStore.toggleActive()">Exit</button> <button class="btn-cyan px-3.5" @click="() => mapEditorStore.toggleActive()">Exit</button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onClickOutside } from '@vueuse/core' import { onClickOutside } from '@vueuse/core'
import { onBeforeUnmount, onMounted, ref } from 'vue' import { onBeforeUnmount, onMounted, ref } from 'vue'
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const emit = defineEmits(['save', 'clear']) const emit = defineEmits(['save', 'clear'])
@ -99,24 +99,24 @@ let selectEraserOpen = ref(false)
// drawMode // drawMode
function setDrawMode(value: string) { function setDrawMode(value: string) {
zoneEditorStore.isTileListModalShown = value === 'tile' mapEditorStore.isTileListModalShown = value === 'tile'
zoneEditorStore.isObjectListModalShown = value === 'object' mapEditorStore.isObjectListModalShown = value === 'object'
zoneEditorStore.setDrawMode(value) mapEditorStore.setDrawMode(value)
selectPencilOpen.value = false selectPencilOpen.value = false
} }
// drawMode // drawMode
function setEraserMode(value: string) { function setEraserMode(value: string) {
zoneEditorStore.setEraserMode(value) mapEditorStore.setEraserMode(value)
selectEraserOpen.value = false selectEraserOpen.value = false
} }
function handleClick(tool: string) { function handleClick(tool: string) {
if (tool === 'settings') { if (tool === 'settings') {
zoneEditorStore.toggleSettingsModal() mapEditorStore.toggleSettingsModal()
} else { } else {
zoneEditorStore.setTool(tool) mapEditorStore.setTool(tool)
} }
selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false
@ -125,7 +125,7 @@ function handleClick(tool: string) {
function cycleToolMode(tool: 'pencil' | 'eraser') { function cycleToolMode(tool: 'pencil' | 'eraser') {
const modes = ['tile', 'object', 'teleport', 'blocking tile'] const modes = ['tile', 'object', 'teleport', 'blocking tile']
const currentMode = tool === 'pencil' ? zoneEditorStore.drawMode : zoneEditorStore.eraserMode const currentMode = tool === 'pencil' ? mapEditorStore.drawMode : mapEditorStore.eraserMode
const currentIndex = modes.indexOf(currentMode) const currentIndex = modes.indexOf(currentMode)
const nextIndex = (currentIndex + 1) % modes.length const nextIndex = (currentIndex + 1) % modes.length
const nextMode = modes[nextIndex] const nextMode = modes[nextIndex]
@ -138,8 +138,8 @@ function cycleToolMode(tool: 'pencil' | 'eraser') {
} }
function initKeyShortcuts(event: KeyboardEvent) { function initKeyShortcuts(event: KeyboardEvent) {
// Check if zone is set // Check if map is set
if (!zoneEditorStore.zone) return if (!mapEditorStore.map) return
// prevent if focused on composables // prevent if focused on composables
if (document.activeElement?.tagName === 'INPUT') return if (document.activeElement?.tagName === 'INPUT') return
@ -154,7 +154,7 @@ function initKeyShortcuts(event: KeyboardEvent) {
if (keyActions.hasOwnProperty(event.key)) { if (keyActions.hasOwnProperty(event.key)) {
const tool = keyActions[event.key] const tool = keyActions[event.key]
if ((tool === 'pencil' || tool === 'eraser') && zoneEditorStore.tool === tool) { if ((tool === 'pencil' || tool === 'eraser') && mapEditorStore.tool === tool) {
cycleToolMode(tool) cycleToolMode(tool)
} else { } else {
handleClick(tool) handleClick(tool)

View File

@ -1,73 +0,0 @@
<template>
<ZoneTiles @tileMap:create="tileMap = $event" />
<ZoneObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<ZoneEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Toolbar @save="save" @clear="clear" />
<ZoneList />
<TileList />
<ObjectList />
<ZoneSettings />
<TeleportModal />
</template>
<script setup lang="ts">
import { type Zone } from '@/application/types'
import ObjectList from '@/components/gameMaster/zoneEditor/partials/ObjectList.vue'
import TeleportModal from '@/components/gameMaster/zoneEditor/partials/TeleportModal.vue'
import TileList from '@/components/gameMaster/zoneEditor/partials/TileList.vue'
// Components
import Toolbar from '@/components/gameMaster/zoneEditor/partials/Toolbar.vue'
import ZoneList from '@/components/gameMaster/zoneEditor/partials/ZoneList.vue'
import ZoneSettings from '@/components/gameMaster/zoneEditor/partials/ZoneSettings.vue'
import ZoneEventTiles from '@/components/gameMaster/zoneEditor/zonePartials/ZoneEventTiles.vue'
import ZoneObjects from '@/components/gameMaster/zoneEditor/zonePartials/ZoneObjects.vue'
import ZoneTiles from '@/components/gameMaster/zoneEditor/zonePartials/ZoneTiles.vue'
import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import { onUnmounted, ref } from 'vue'
const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore()
const tileMap = ref(null as Phaser.Tilemaps.Tilemap | null)
function clear() {
if (!zoneEditorStore.zone) return
// Clear objects, event tiles and tiles
zoneEditorStore.zone.zoneObjects = []
zoneEditorStore.zone.zoneEventTiles = []
zoneEditorStore.triggerClearTiles()
}
function save() {
if (!zoneEditorStore.zone) return
const data = {
zoneId: zoneEditorStore.zone.id,
name: zoneEditorStore.zoneSettings.name,
width: zoneEditorStore.zoneSettings.width,
height: zoneEditorStore.zoneSettings.height,
tiles: zoneEditorStore.zone.tiles,
pvp: zoneEditorStore.zone.pvp,
zoneEffects: zoneEditorStore.zone.zoneEffects.map(({ id, zoneId, effect, strength }) => ({ id, zoneId, effect, strength })),
zoneEventTiles: zoneEditorStore.zone.zoneEventTiles.map(({ id, zoneId, type, positionX, positionY, teleport }) => ({ id, zoneId, type, positionX, positionY, teleport })),
zoneObjects: zoneEditorStore.zone.zoneObjects.map(({ id, zoneId, objectId, depth, isRotated, positionX, positionY }) => ({ id, zoneId, objectId, depth, isRotated, positionX, positionY }))
}
if (zoneEditorStore.isSettingsModalShown) {
zoneEditorStore.toggleSettingsModal()
}
gameStore.connection?.emit('gm:zone_editor:zone:update', data, (response: Zone) => {
zoneEditorStore.setZone(response)
})
}
onUnmounted(() => {
zoneEditorStore.reset()
})
</script>

View File

@ -1,61 +0,0 @@
<template>
<CreateZone v-if="zoneEditorStore.isCreateZoneModalShown" />
<Modal :is-modal-open="zoneEditorStore.isZoneListModalShown" @modal:close="() => zoneEditorStore.toggleZoneListModal()" :is-resizable="false" :modal-width="300" :modal-height="360" :bg-style="'none'">
<template #modalHeader>
<h3 class="text-lg text-white">Zones</h3>
</template>
<template #modalBody>
<div class="my-4 mx-auto">
<div class="text-center mb-4 px-2 flex gap-2.5">
<button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="fetchZones">Refresh</button>
<button class="btn-cyan py-1.5 min-w-[calc(50%_-_5px)]" @click="() => zoneEditorStore.toggleCreateZoneModal()">New</button>
</div>
<div class="relative p-2.5 cursor-pointer flex gap-y-2.5 gap-x-5 flex-wrap" v-for="(zone, index) in zoneEditorStore.zoneList" :key="zone.id">
<div class="absolute left-0 top-0 w-full h-px bg-gray-500" v-if="index === 0"></div>
<div class="flex gap-3 items-center w-full" @click="() => loadZone(zone.id)">
<span>{{ zone.name }}</span>
<span class="ml-auto gap-1 flex">
<button class="btn-red w-7 h-7 z-50 flex items-center justify-center" @click.stop="() => deleteZone(zone.id)">x</button>
</span>
</div>
<div class="absolute left-0 bottom-0 w-full h-px bg-gray-500"></div>
</div>
</div>
</template>
</Modal>
</template>
<script setup lang="ts">
import type { Zone } from '@/application/types'
import CreateZone from '@/components/gameMaster/zoneEditor/partials/CreateZone.vue'
import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import { onMounted } from 'vue'
const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore()
onMounted(async () => {
fetchZones()
})
function fetchZones() {
gameStore.connection?.emit('gm:zone_editor:zone:list', {}, (response: Zone[]) => {
zoneEditorStore.setZoneList(response)
})
}
function loadZone(id: number) {
gameStore.connection?.emit('gm:zone_editor:zone:request', { zoneId: id }, (response: Zone) => {
zoneEditorStore.setZone(response)
})
zoneEditorStore.toggleZoneListModal()
}
function deleteZone(id: number) {
gameStore.connection?.emit('gm:zone_editor:zone:delete', { zoneId: id }, () => {
fetchZones()
})
}
</script>

View File

@ -1,45 +0,0 @@
<template>
<Image v-if="gameStore.getLoadedAsset(props.zoneObject.object.id)" v-bind="imageProps" />
</template>
<script setup lang="ts">
import type { AssetDataT, ZoneObject } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer'
import { computed } from 'vue'
const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap
zoneObject: ZoneObject
selectedZoneObject: ZoneObject | null
movingZoneObject: ZoneObject | null
}>()
const gameStore = useGameStore()
const scene = useScene()
const imageProps = computed(() => ({
alpha: props.movingZoneObject?.id === props.zoneObject.id ? 0.5 : 1,
tint: props.selectedZoneObject?.id === props.zoneObject.id ? 0x00ff00 : 0xffffff,
depth: calculateIsometricDepth(props.zoneObject.positionX, props.zoneObject.positionY, props.zoneObject.object.frameWidth, props.zoneObject.object.frameHeight),
x: tileToWorldX(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
y: tileToWorldY(props.tilemap, props.zoneObject.positionX, props.zoneObject.positionY),
flipX: props.zoneObject.isRotated,
texture: props.zoneObject.object.id,
originY: Number(props.zoneObject.object.originX),
originX: Number(props.zoneObject.object.originY)
}))
loadTexture(scene, {
key: props.zoneObject.object.id,
data: '/assets/objects/' + props.zoneObject.object.id + '.png',
group: 'objects',
updatedAt: props.zoneObject.object.updatedAt,
frameWidth: props.zoneObject.object.frameWidth,
frameHeight: props.zoneObject.object.frameHeight
} as AssetDataT).catch((error) => {
console.error('Error loading texture:', error)
})
</script>

View File

@ -23,14 +23,14 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Chat } from '@/application/types' import type { Chat } from '@/application/types'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useMapStore } from '@/stores/mapStore'
import { onClickOutside, useFocus } from '@vueuse/core' import { onClickOutside, useFocus } from '@vueuse/core'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue' import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
const scene = useScene() const scene = useScene()
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneStore = useZoneStore() const mapStore = useMapStore()
const message = ref('') const message = ref('')
const chats = ref([] as Chat[]) const chats = ref([] as Chat[])
@ -83,7 +83,7 @@ gameStore.connection!.on('chat:message', (data: Chat) => {
chats.value.push(data) chats.value.push(data)
scrollToBottom() scrollToBottom()
if (!zoneStore.characterLoaded) return if (!mapStore.characterLoaded) return
const charChatContainer = scene.children.getByName(data.character.name + '_chatContainer') as Phaser.GameObjects.Container const charChatContainer = scene.children.getByName(data.character.name + '_chatContainer') as Phaser.GameObjects.Container
if (!charChatContainer) return if (!charChatContainer) return

View File

@ -126,7 +126,7 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import { type CharacterHair, type Character as CharacterT, type Zone } from '@/application/types' import { type CharacterHair, type Character as CharacterT, type Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onBeforeUnmount, ref, watch } from 'vue' import { onBeforeUnmount, ref, watch } from 'vue'
@ -166,7 +166,7 @@ function loginWithCharacter() {
characterId: selectedCharacterId.value, characterId: selectedCharacterId.value,
characterHairId: selectedHairId.value characterHairId: selectedHairId.value
}, },
(response: { character: CharacterT; zone: Zone; characters: CharacterT[] }) => { (response: { character: CharacterT; map: Map; characters: CharacterT[] }) => {
gameStore.setCharacter(response.character) gameStore.setCharacter(response.character)
} }
) )

View File

@ -6,7 +6,7 @@
<Hud /> <Hud />
<Hotkeys /> <Hotkeys />
<Clock /> <Clock />
<Zone /> <Map />
<Chat /> <Chat />
<ExpBar /> <ExpBar />
@ -21,7 +21,7 @@
import config from '@/application/config' import config from '@/application/config'
import 'phaser' import 'phaser'
import Effects from '@/components/Effects.vue' import Effects from '@/components/Effects.vue'
import Zone from '@/components/game/zone/Zone.vue' import Map from '@/components/game/map/Map.vue'
import CharacterProfile from '@/components/gui/CharacterProfile.vue' import CharacterProfile from '@/components/gui/CharacterProfile.vue'
import Chat from '@/components/gui/Chat.vue' import Chat from '@/components/gui/Chat.vue'
// import Minimap from '@/components/gui/Minimap.vue' // import Minimap from '@/components/gui/Minimap.vue'
@ -75,7 +75,7 @@ function preloadScene(scene: Phaser.Scene) {
/** /**
* Load the base assets into the Phaser scene * Load the base assets into the Phaser scene
*/ */
scene.load.image('blank_tile', '/assets/zone/blank_tile.png') scene.load.image('blank_tile', '/assets/map/blank_tile.png')
scene.load.image('waypoint', '/assets/waypoint.png') scene.load.image('waypoint', '/assets/waypoint.png')
} }

View File

@ -2,7 +2,7 @@
<div class="flex justify-center items-center h-dvh relative"> <div class="flex justify-center items-center h-dvh relative">
<Game :config="gameConfig" @create="createGame"> <Game :config="gameConfig" @create="createGame">
<Scene name="main" @preload="preloadScene" @create="createScene"> <Scene name="main" @preload="preloadScene" @create="createScene">
<ZoneEditor :key="JSON.stringify(`${zoneEditorStore.zone?.id}_${zoneEditorStore.zone?.createdAt}_${zoneEditorStore.zone?.updatedAt ?? ''}`)" /> <MapEditor :key="JSON.stringify(`${mapEditorStore.map?.id}_${mapEditorStore.map?.createdAt}_${mapEditorStore.map?.updatedAt ?? ''}`)" />
</Scene> </Scene>
</Game> </Game>
</div> </div>
@ -12,15 +12,15 @@
import config from '@/application/config' import config from '@/application/config'
import 'phaser' import 'phaser'
import type { AssetDataT } from '@/application/types' import type { AssetDataT } from '@/application/types'
import ZoneEditor from '@/components/gameMaster/zoneEditor/ZoneEditor.vue' import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue'
import { loadTexture } from '@/composables/gameComposable' import { loadTexture } from '@/composables/gameComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin' import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin'
import { Game, Scene } from 'phavuer' import { Game, Scene } from 'phavuer'
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const gameConfig = { const gameConfig = {
name: config.name, name: config.name,
@ -61,9 +61,9 @@ const preloadScene = async (scene: Phaser.Scene) => {
/** /**
* Load the base assets into the Phaser scene * Load the base assets into the Phaser scene
*/ */
scene.load.image('BLOCK', '/assets/zone/bt_tile.png') scene.load.image('BLOCK', '/assets/map/bt_tile.png')
scene.load.image('TELEPORT', '/assets/zone/tp_tile.png') scene.load.image('TELEPORT', '/assets/map/tp_tile.png')
scene.load.image('blank_tile', '/assets/zone/blank_tile.png') scene.load.image('blank_tile', '/assets/map/blank_tile.png')
scene.load.image('waypoint', '/assets/waypoint.png') scene.load.image('waypoint', '/assets/waypoint.png')
/** /**

View File

@ -1,5 +1,5 @@
import config from '@/application/config' import config from '@/application/config'
import type { AssetDataT, HttpResponse, Zone as ZoneT } from '@/application/types' import type { AssetDataT, HttpResponse, Map as MapT } from '@/application/types'
import { loadTexture } from '@/composables/gameComposable' import { loadTexture } from '@/composables/gameComposable'
import Tilemap = Phaser.Tilemaps.Tilemap import Tilemap = Phaser.Tilemaps.Tilemap
@ -39,26 +39,26 @@ export function tileToWorldY(layer: TilemapLayer | Tilemap, pos_x: number, pos_y
/** /**
* Can also be used to replace tiles * Can also be used to replace tiles
* @param zone * @param map
* @param layer * @param layer
* @param x * @param x
* @param y * @param y
* @param tileName * @param tileName
*/ */
export function placeTile(zone: Tilemap, layer: TilemapLayer, x: number, y: number, tileName: string) { export function placeTile(map: Tilemap, layer: TilemapLayer, x: number, y: number, tileName: string) {
let tileImg = zone.getTileset(tileName) as Tileset let tileImg = map.getTileset(tileName) as Tileset
if (!tileImg) { if (!tileImg) {
tileImg = zone.getTileset('blank_tile') as Tileset tileImg = map.getTileset('blank_tile') as Tileset
} }
layer.putTileAt(tileImg.firstgid, x, y) layer.putTileAt(tileImg.firstgid, x, y)
} }
export function setLayerTiles(zone: Tilemap, layer: TilemapLayer, tiles: string[][]) { export function setLayerTiles(map: Tilemap, layer: TilemapLayer, tiles: string[][]) {
if (!tiles) return if (!tiles) return
tiles.forEach((row: string[], y: number) => { tiles.forEach((row: string[], y: number) => {
row.forEach((tile: string, x: number) => { row.forEach((tile: string, x: number) => {
placeTile(zone, layer, x, y, tile) placeTile(map, layer, x, y, tile)
}) })
}) })
} }
@ -75,7 +75,7 @@ export const calculateIsometricDepth = (x: number, y: number, width: number = 0,
return baseDepth + (width + height) / (2 * config.tile_size.x) return baseDepth + (width + height) / (2 * config.tile_size.x)
} }
export function FlattenZoneArray(tiles: string[][]) { export function FlattenMapArray(tiles: string[][]) {
const normalArray = [] const normalArray = []
for (const row of tiles) { for (const row of tiles) {
@ -85,9 +85,9 @@ export function FlattenZoneArray(tiles: string[][]) {
return normalArray return normalArray
} }
export async function loadZoneTilesIntoScene(zone_id: number, scene: Phaser.Scene) { export async function loadMapTilesIntoScene(map_id: number, scene: Phaser.Scene) {
// Fetch the list of tiles from the server // Fetch the list of tiles from the server
const tileArray: HttpResponse<AssetDataT[]> = await fetch(config.server_endpoint + '/assets/list_tiles/' + zone_id).then((response) => response.json()) const tileArray: HttpResponse<AssetDataT[]> = await fetch(config.server_endpoint + '/assets/list_tiles/' + map_id).then((response) => response.json())
// Load each tile into the scene // Load each tile into the scene
for (const tile of tileArray.data ?? []) { for (const tile of tileArray.data ?? []) {

View File

@ -1,5 +1,5 @@
import config from '@/application/config' import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/zoneComposable' import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { ref, type Ref } from 'vue' import { ref, type Ref } from 'vue'
@ -48,7 +48,7 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
if (distance <= dragThreshold) { if (distance <= dragThreshold) {
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY) const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (pointerTile) { if (pointerTile) {
gameStore.connection?.emit('zone:character:move', { gameStore.connection?.emit('map:character:move', {
positionX: pointerTile.x, positionX: pointerTile.x,
positionY: pointerTile.y positionY: pointerTile.y
}) })

View File

@ -1,13 +1,13 @@
import config from '@/application/config' import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/zoneComposable' import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, type Ref } from 'vue' import { computed, type Ref } from 'vue'
export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) { export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore() const gameStore = useGameStore()
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const isMoveTool = computed(() => zoneEditorStore.tool === 'move') const isMoveTool = computed(() => mapEditorStore.tool === 'move')
function updateWaypoint(pointer: Phaser.Input.Pointer) { function updateWaypoint(pointer: Phaser.Input.Pointer) {
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y) const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y)
@ -25,7 +25,7 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.
} }
} }
function dragZone(pointer: Phaser.Input.Pointer) { function dragMap(pointer: Phaser.Input.Pointer) {
if (gameStore.game.isPlayerDraggingCamera) { if (gameStore.game.isPlayerDraggingCamera) {
const { x, y, prevPosition } = pointer const { x, y, prevPosition } = pointer
const { scrollX, scrollY, zoom } = camera const { scrollX, scrollY, zoom } = camera
@ -35,7 +35,7 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.
function handlePointerMove(pointer: Phaser.Input.Pointer) { function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) { if (isMoveTool.value || pointer.event.shiftKey) {
dragZone(pointer) dragMap(pointer)
} }
updateWaypoint(pointer) updateWaypoint(pointer)
} }

View File

@ -1,5 +1,5 @@
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore' import { useMapStore } from '@/stores/mapStore'
export function useCameraControls(scene: Phaser.Scene) { export function useCameraControls(scene: Phaser.Scene) {
const gameStore = useGameStore() const gameStore = useGameStore()

View File

@ -1,20 +1,20 @@
import { useZoneEditorStore } from '@/stores/zoneEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, watch, type Ref } from 'vue' import { computed, watch, type Ref } from 'vue'
import { useGamePointerHandlers } from './pointerHandlers/useGamePointerHandlers' import { useGamePointerHandlers } from './pointerHandlers/useGamePointerHandlers'
import { useZoneEditorPointerHandlers } from './pointerHandlers/useZoneEditorPointerHandlers' import { useMapEditorPointerHandlers } from './pointerHandlers/useMapEditorPointerHandlers'
export function usePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) { export function usePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const zoneEditorStore = useZoneEditorStore() const mapEditorStore = useMapEditorStore()
const gameHandlers = useGamePointerHandlers(scene, layer, waypoint, camera) const gameHandlers = useGamePointerHandlers(scene, layer, waypoint, camera)
const zoneEditorHandlers = useZoneEditorPointerHandlers(scene, layer, waypoint, camera) const mapEditorHandlers = useMapEditorPointerHandlers(scene, layer, waypoint, camera)
const currentHandlers = computed(() => (zoneEditorStore.active ? zoneEditorHandlers : gameHandlers)) const currentHandlers = computed(() => (mapEditorStore.active ? mapEditorHandlers : gameHandlers))
const setupPointerHandlers = () => currentHandlers.value.setupPointerHandlers() const setupPointerHandlers = () => currentHandlers.value.setupPointerHandlers()
const cleanupPointerHandlers = () => currentHandlers.value.cleanupPointerHandlers() const cleanupPointerHandlers = () => currentHandlers.value.cleanupPointerHandlers()
watch( watch(
() => zoneEditorStore.active, () => mapEditorStore.active,
() => { () => {
cleanupPointerHandlers() cleanupPointerHandlers()
setupPointerHandlers() setupPointerHandlers()

View File

@ -1,42 +1,42 @@
import type { Object, Tile, Zone, ZoneEffect, ZoneObject } from '@/application/types' import type { Object, Tile, Map, MapEffect, PlacedMapObject } from '@/application/types'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export type TeleportSettings = { export type TeleportSettings = {
toZoneId: number toMapId: number
toPositionX: number toPositionX: number
toPositionY: number toPositionY: number
toRotation: number toRotation: number
} }
export const useZoneEditorStore = defineStore('zoneEditor', { export const useMapEditorStore = defineStore('mapEditor', {
state: () => { state: () => {
return { return {
active: false, active: false,
zone: null as Zone | null, map: null as Map | null,
tool: 'move', tool: 'move',
drawMode: 'tile', drawMode: 'tile',
eraserMode: 'tile', eraserMode: 'tile',
zoneList: [] as Zone[], mapList: [] as Map[],
tileList: [] as Tile[], tileList: [] as Tile[],
objectList: [] as Object[], objectList: [] as Object[],
selectedTile: '', selectedTile: '',
selectedObject: null as Object | null, selectedObject: null as Object | null,
isTileListModalShown: false, isTileListModalShown: false,
isObjectListModalShown: false, isObjectListModalShown: false,
isZoneListModalShown: false, isMapListModalShown: false,
isCreateZoneModalShown: false, isCreateMapModalShown: false,
isSettingsModalShown: false, isSettingsModalShown: false,
shouldClearTiles: false, shouldClearTiles: false,
zoneSettings: { mapSettings: {
name: '', name: '',
width: 0, width: 0,
height: 0, height: 0,
pvp: false, pvp: false,
zoneEffects: [] as ZoneEffect[] mapEffects: [] as MapEffect[]
}, },
teleportSettings: { teleportSettings: {
toZoneId: 0, toMapId: 0,
toPositionX: 0, toPositionX: 0,
toPositionY: 0, toPositionY: 0,
toRotation: 0 toRotation: 0
@ -46,29 +46,29 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
actions: { actions: {
toggleActive() { toggleActive() {
const gameStore = useGameStore() const gameStore = useGameStore()
if (!this.active) gameStore.connection?.emit('zone:character:leave') if (!this.active) gameStore.connection?.emit('map:character:leave')
if (this.active) this.reset() if (this.active) this.reset()
this.active = !this.active this.active = !this.active
}, },
setZone(zone: Zone | null) { setMap(map: Map | null) {
this.zone = zone this.map = map
}, },
setZoneName(name: string) { setMapName(name: string) {
this.zoneSettings.name = name this.mapSettings.name = name
}, },
setZoneWidth(width: number) { setMapWidth(width: number) {
this.zoneSettings.width = width this.mapSettings.width = width
}, },
setZoneHeight(height: number) { setMapHeight(height: number) {
this.zoneSettings.height = height this.mapSettings.height = height
}, },
setZonePvp(pvp: boolean) { setMapPvp(pvp: boolean) {
if (!this.zone) return if (!this.map) return
this.zone.pvp = pvp this.map.pvp = pvp
}, },
setZoneEffects(zoneEffects: ZoneEffect[]) { setMapEffects(mapEffects: MapEffect[]) {
if (!this.zone) return if (!this.map) return
this.zoneSettings.zoneEffects = zoneEffects this.mapSettings.mapEffects = mapEffects
}, },
setTool(tool: string) { setTool(tool: string) {
this.tool = tool this.tool = tool
@ -79,8 +79,8 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
setEraserMode(mode: string) { setEraserMode(mode: string) {
this.eraserMode = mode this.eraserMode = mode
}, },
setZoneList(zones: Zone[]) { setMapList(maps: Map[]) {
this.zoneList = zones this.mapList = maps
}, },
setTileList(tiles: Tile[]) { setTileList(tiles: Tile[]) {
this.tileList = tiles this.tileList = tiles
@ -97,12 +97,12 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
toggleSettingsModal() { toggleSettingsModal() {
this.isSettingsModalShown = !this.isSettingsModalShown this.isSettingsModalShown = !this.isSettingsModalShown
}, },
toggleZoneListModal() { toggleMapListModal() {
this.isZoneListModalShown = !this.isZoneListModalShown this.isMapListModalShown = !this.isMapListModalShown
this.isCreateZoneModalShown = false this.isCreateMapModalShown = false
}, },
toggleCreateZoneModal() { toggleCreateMapModal() {
this.isCreateZoneModalShown = !this.isCreateZoneModalShown this.isCreateMapModalShown = !this.isCreateMapModalShown
}, },
setTeleportSettings(teleportSettings: TeleportSettings) { setTeleportSettings(teleportSettings: TeleportSettings) {
this.teleportSettings = teleportSettings this.teleportSettings = teleportSettings
@ -114,9 +114,9 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
resetClearTilesFlag() { resetClearTilesFlag() {
this.shouldClearTiles = false this.shouldClearTiles = false
}, },
reset(resetZone = false) { reset(resetMap = false) {
if (resetZone) this.zone = null if (resetMap) this.map = null
this.zoneList = [] this.mapList = []
this.tileList = [] this.tileList = []
this.objectList = [] this.objectList = []
this.tool = 'move' this.tool = 'move'
@ -126,8 +126,8 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
this.isTileListModalShown = false this.isTileListModalShown = false
this.isObjectListModalShown = false this.isObjectListModalShown = false
this.isSettingsModalShown = false this.isSettingsModalShown = false
this.isZoneListModalShown = false this.isMapListModalShown = false
this.isCreateZoneModalShown = false this.isCreateMapModalShown = false
this.shouldClearTiles = false this.shouldClearTiles = false
} }
} }

View File

@ -1,11 +1,11 @@
import type { Zone, ZoneCharacter } from '@/application/types' import type { Map, MapCharacter } from '@/application/types'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useZoneStore = defineStore('zone', { export const useMapStore = defineStore('map', {
state: () => { state: () => {
return { return {
zone: null as Zone | null, map: null as Map | null,
characters: [] as ZoneCharacter[], characters: [] as MapCharacter[],
characterLoaded: false characterLoaded: false
} }
}, },
@ -16,21 +16,21 @@ export const useZoneStore = defineStore('zone', {
getCharacterCount: (state) => { getCharacterCount: (state) => {
return state.characters.length return state.characters.length
}, },
isZoneSet: (state) => { isMapSet: (state) => {
return state.zone !== null return state.map !== null
} }
}, },
actions: { actions: {
setZone(zone: Zone | null) { setMap(map: Map | null) {
this.zone = zone this.map = map
}, },
setCharacters(characters: ZoneCharacter[]) { setCharacters(characters: MapCharacter[]) {
this.characters = characters this.characters = characters
}, },
addCharacter(character: ZoneCharacter) { addCharacter(character: MapCharacter) {
this.characters.push(character) this.characters.push(character)
}, },
updateCharacter(updatedCharacter: ZoneCharacter) { updateCharacter(updatedCharacter: MapCharacter) {
const index = this.characters.findIndex((char) => char.character.id === updatedCharacter.character.id) const index = this.characters.findIndex((char) => char.character.id === updatedCharacter.character.id)
if (index !== -1) this.characters[index] = updatedCharacter if (index !== -1) this.characters[index] = updatedCharacter
}, },
@ -50,7 +50,7 @@ export const useZoneStore = defineStore('zone', {
} }
}, },
reset() { reset() {
this.zone = null this.map = null
this.characters = [] this.characters = []
this.characterLoaded = false this.characterLoaded = false
} }