feat(falukant): render houses with 3D models
Some checks failed
Deploy to production / deploy (push) Failing after 1m17s

This commit is contained in:
Torsten Schulz (local)
2026-09-25 07:44:53 +02:00
parent 4e20111331
commit d15c56a7b3
5 changed files with 274 additions and 90 deletions

View File

@@ -19,7 +19,12 @@
</p>
</section>
<div class="existing-house">
<div :style="houseType ? houseStyle(houseType.position, 341) : {}" class="house"></div>
<House3D
v-if="houseType?.labelTr"
class="house"
:model="houseModel(houseType)"
:label="$t(`falukant.house.type.${houseType.labelTr}`)"
/>
<div class="status-panel surface-card">
<h3>{{ $t('falukant.house.statusreport') }}</h3>
<div class="status-cards">
@@ -128,8 +133,12 @@
<h3>{{ $t('falukant.house.buyablehouses') }}</h3>
<div class="houses-list">
<div v-for="house in buyableHouses" :key="house.id" class="house-item">
<div :style="house.houseType ? houseStyle(house.houseType.position, 114) : {}"
class="house-preview"></div>
<House3D
v-if="house.houseType?.labelTr"
class="house-preview"
:model="houseModel(house.houseType)"
:label="$t(`falukant.house.type.${house.houseType.labelTr}`)"
/>
<div class="house-info">
<h4>{{ $t(`falukant.house.type.${house.houseType.labelTr}`) }}</h4>
<div class="buyable-house-stats">
@@ -155,13 +164,15 @@
<script>
import StatusBar from '@/components/falukant/StatusBar.vue';
import House3D from '@/components/falukant/House3D.vue';
import apiClient from '@/utils/axios.js';
import { mapState } from 'vuex';
import { showError, showSuccess, confirmAction } from '@/utils/feedback.js';
import { getFalukantHouseModel } from '@/utils/falukantHouseModels.js';
export default {
name: 'HouseView',
components: { StatusBar },
components: { StatusBar, House3D },
data() {
return {
userHouse: null,
@@ -222,17 +233,8 @@ export default {
if (v >= 1) return this.$t('falukant.conditionBand.catastrophic');
return this.$t('falukant.conditionBand.unknown');
},
houseStyle(position, picSize) {
const columns = 3;
const size = picSize;
const index = position - 1;
const x = (index % columns) * size;
const y = Math.floor(index / columns) * size;
return {
backgroundImage: 'url("/images/falukant/houses.png")',
backgroundPosition: `-${x}px -${y}px`,
backgroundSize: `${columns * size}px auto`
};
houseModel(houseType) {
return getFalukantHouseModel(houseType);
},
formatPrice(value) {
return new Intl.NumberFormat('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value);
@@ -456,9 +458,6 @@ h2 {
.house {
width: 341px;
height: 341px;
background-repeat: no-repeat;
image-rendering: crisp-edges;
border: 1px solid var(--color-border);
border-radius: 4px;
}
@@ -597,14 +596,7 @@ h2 {
.house-preview {
width: 100px;
height: 100px;
background-repeat: no-repeat;
image-rendering: crisp-edges;
border: 1px solid var(--color-border);
border-radius: 4px;
background-size: contain;
/* scale image to container */
background-position: center;
/* center sprite */
}
.house-info {

View File

@@ -29,7 +29,12 @@
<div v-if="falukantUser?.character && !falukantUser?.debtorsPrison?.inDebtorsPrison" class="imagecontainer">
<div v-if="showPortraitAvatar" :style="getAvatarStyle" class="avatar"></div>
<div v-if="showCharacterFigure3d" class="house-with-character">
<div :style="getHouseStyle" class="house"></div>
<House3D
v-if="falukantUser.userHouse?.houseType"
class="house"
:model="houseModel"
:label="$t(`falukant.house.type.${falukantUser.userHouse.houseType.labelTr}`)"
/>
<div class="character-foreground">
<Character3D
:gender="falukantUser.character.gender"
@@ -365,6 +370,8 @@
<script>
import StatusBar from '@/components/falukant/StatusBar.vue';
import Character3D from '@/components/Character3D.vue';
import House3D from '@/components/falukant/House3D.vue';
import { getFalukantHouseModel } from '@/utils/falukantHouseModels.js';
import apiClient from '@/utils/axios.js';
import { showError, showSuccess } from '@/utils/feedback.js';
import { mapState } from 'vuex';
@@ -426,6 +433,7 @@ export default {
components: {
StatusBar,
Character3D,
House3D,
},
data() {
return {
@@ -463,25 +471,8 @@ export default {
height: `${height}px`,
};
},
getHouseStyle() {
if (!this.falukantUser || !this.falukantUser.userHouse?.houseType) return {};
const imageUrl = '/images/falukant/houses.png';
const pos = this.falukantUser.userHouse.houseType.position;
const index = pos - 1;
const columns = 3;
const spriteSize = 300;
const x = (index % columns) * spriteSize;
const y = Math.floor(index / columns) * spriteSize;
return {
backgroundImage: `url(${imageUrl})`,
backgroundPosition: `-${x}px -${y}px`,
backgroundSize: `${columns * spriteSize}px auto`,
width: `300px`,
height: `300px`,
border: '1px solid #ccc',
borderRadius: '4px',
imageRendering: 'crisp-edges',
};
houseModel() {
return getFalukantHouseModel(this.falukantUser?.userHouse?.houseType);
},
moneyValue() {
const m = this.falukantUser?.money;