diff --git a/app/main.ts b/app/main.ts index ba1a8b6..c4ffd82 100644 --- a/app/main.ts +++ b/app/main.ts @@ -8,6 +8,7 @@ import {ModelComponentFileDirectory} from "./storage/ModelComponentFileDirectory import {GamesystemStorage} from "./storage/storing/GamesystemStorage"; import {Character} from "../src/app/project/game-model/characters/Character"; import {CharacterStorage} from "./storage/storing/CharacterStorage"; +import {ItemStorage} from "./storage/storing/ItemStorage"; let win: BrowserWindow | null = null; const args = process.argv.slice(1), @@ -247,6 +248,9 @@ function recieveGameModelToStore(gameModel: StoredGameModel) { const characterStorage = new CharacterStorage(path.join(projectDirectory, ModelComponentFileDirectory.CHARACTER_DIR_NAME)) characterStorage.storeCharacters(gameModel.storedCharacters) + + const itemStorage = new ItemStorage(path.join(projectDirectory, ModelComponentFileDirectory.ITEM_DIR_NAME)) + itemStorage.storeItem(gameModel.storedItems); } /*function deleteComponent(component: DeleteModel) { diff --git a/app/storage/ModelComponentFileDirectory.js b/app/storage/ModelComponentFileDirectory.js index 8d28902..fa14422 100644 --- a/app/storage/ModelComponentFileDirectory.js +++ b/app/storage/ModelComponentFileDirectory.js @@ -7,4 +7,5 @@ exports.ModelComponentFileDirectory = ModelComponentFileDirectory; ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME = "script-accounts"; ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME = "gamesystems"; ModelComponentFileDirectory.CHARACTER_DIR_NAME = "characters"; +ModelComponentFileDirectory.ITEM_DIR_NAME = "items"; //# sourceMappingURL=ModelComponentFileDirectory.js.map \ No newline at end of file diff --git a/app/storage/ModelComponentFileDirectory.ts b/app/storage/ModelComponentFileDirectory.ts index a0b9c8c..38e675a 100644 --- a/app/storage/ModelComponentFileDirectory.ts +++ b/app/storage/ModelComponentFileDirectory.ts @@ -2,4 +2,5 @@ export class ModelComponentFileDirectory { public static SCRIPTACCOUNT_DIR_NAME = "script-accounts" public static GAMESYSTEM_DIR_NAME = "gamesystems"; public static CHARACTER_DIR_NAME = "characters"; + public static ITEM_DIR_NAME = "items"; } diff --git a/app/storage/StoredGameModel.js b/app/storage/StoredGameModel.js index 57bfbe7..2ba280b 100644 --- a/app/storage/StoredGameModel.js +++ b/app/storage/StoredGameModel.js @@ -2,11 +2,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.StoredGameModel = void 0; class StoredGameModel { - constructor(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters) { + constructor(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, storedItems) { this.gameModelName = gameModelName; this.storedGamesystems = storedGamesystems; this.storedScriptAccounts = storedScriptAccounts; this.storedCharacters = storedCharacters; + this.storedItems = storedItems; } } exports.StoredGameModel = StoredGameModel; diff --git a/app/storage/StoredGameModel.ts b/app/storage/StoredGameModel.ts index d9d762b..5449edd 100644 --- a/app/storage/StoredGameModel.ts +++ b/app/storage/StoredGameModel.ts @@ -6,13 +6,15 @@ export class StoredGameModel { storedGamesystems: StoreComponent[] storedScriptAccounts: StoreComponent[] storedCharacters: StoreComponent[] + storedItems: StoreComponent[] constructor(gameModelName: string, storedScriptAccounts: StoreComponent[], storedGamesystems: StoreComponent[], - storedCharacters: StoreComponent[]) { + storedCharacters: StoreComponent[], storedItems: StoreComponent[]) { this.gameModelName = gameModelName; this.storedGamesystems = storedGamesystems; this.storedScriptAccounts = storedScriptAccounts; this.storedCharacters = storedCharacters; + this.storedItems = storedItems; } } diff --git a/app/storage/loader/GameModelLoader.js b/app/storage/loader/GameModelLoader.js index 480dc36..5431d73 100644 --- a/app/storage/loader/GameModelLoader.js +++ b/app/storage/loader/GameModelLoader.js @@ -7,6 +7,7 @@ const ModelComponentFileDirectory_1 = require("../ModelComponentFileDirectory"); const ScriptAccountLoader_1 = require("./ScriptAccountLoader"); const GamesystemLoader_1 = require("./GamesystemLoader"); const CharacterLoader_1 = require("./CharacterLoader"); +const ItemLoader_1 = require("./ItemLoader"); class GameModelLoader { constructor(gameModelDir) { this.gameModelDir = gameModelDir; @@ -16,7 +17,8 @@ class GameModelLoader { const storedScriptAccounts = this.loadScriptAccountComponents(); const storedGamesystems = this.loadGamesystems(); const storedCharacters = this.loadCharacters(); - return new StoredGameModel_1.StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters); + const storedItems = this.loadItems(); + return new StoredGameModel_1.StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, storedItems); } loadScriptAccountComponents() { const scriptAccountDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME); @@ -33,6 +35,11 @@ class GameModelLoader { const characterLoader = new CharacterLoader_1.CharacterLoader(characterDir); return characterLoader.loadCharacters(); } + loadItems() { + const itemDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.ITEM_DIR_NAME); + const itemLoader = new ItemLoader_1.ItemLoader(itemDir); + return itemLoader.loadItems(); + } } exports.GameModelLoader = GameModelLoader; //# sourceMappingURL=GameModelLoader.js.map \ No newline at end of file diff --git a/app/storage/loader/GameModelLoader.ts b/app/storage/loader/GameModelLoader.ts index 615c354..14dc146 100644 --- a/app/storage/loader/GameModelLoader.ts +++ b/app/storage/loader/GameModelLoader.ts @@ -6,6 +6,7 @@ import {ModelComponentFileDirectory} from "../ModelComponentFileDirectory"; import {ScriptAccountLoader} from "./ScriptAccountLoader"; import {GamesystemLoader} from "./GamesystemLoader"; import {CharacterLoader} from "./CharacterLoader"; +import {ItemLoader} from "./ItemLoader"; export class GameModelLoader { gameModelDir: string @@ -21,8 +22,9 @@ export class GameModelLoader { const storedScriptAccounts = this.loadScriptAccountComponents(); const storedGamesystems = this.loadGamesystems(); const storedCharacters = this.loadCharacters() + const storedItems = this.loadItems(); - return new StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters); + return new StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, storedItems); } private loadScriptAccountComponents() { @@ -44,7 +46,9 @@ export class GameModelLoader { } - - - + private loadItems(): StoreComponent[] { + const itemDir = path.join(this.gameModelDir, ModelComponentFileDirectory.ITEM_DIR_NAME); + const itemLoader = new ItemLoader(itemDir) + return itemLoader.loadItems(); + } } diff --git a/app/storage/loader/ItemLoader.js b/app/storage/loader/ItemLoader.js new file mode 100644 index 0000000..7536397 --- /dev/null +++ b/app/storage/loader/ItemLoader.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ItemLoader = void 0; +const fs = require("node:fs"); +const StoreComponent_1 = require("../StoreComponent"); +const ModelComponentType_1 = require("../../../src/app/project/game-model/ModelComponentType"); +const FileUtils_1 = require("../FileUtils"); +class ItemLoader { + constructor(itemDir) { + this.itemDir = itemDir; + } + loadItems() { + const itemFiles = FileUtils_1.FileUtils.listFilesInDirectory(this.itemDir); + const loadedItems = []; + itemFiles.forEach(itemFile => { + const loadedItem = this.loadItem(itemFile); + if (loadedItem != undefined) { + loadedItems.push(loadedItem); + } + }); + return loadedItems; + } + loadItem(itemFile) { + if (itemFile.endsWith(".json")) { + const itemData = fs.readFileSync(itemFile, 'utf-8'); + return new StoreComponent_1.StoreComponent(itemData, itemFile, ModelComponentType_1.ModelComponentType.ITEM); + } + } +} +exports.ItemLoader = ItemLoader; +//# sourceMappingURL=ItemLoader.js.map \ No newline at end of file diff --git a/app/storage/loader/ItemLoader.ts b/app/storage/loader/ItemLoader.ts new file mode 100644 index 0000000..aca7a9c --- /dev/null +++ b/app/storage/loader/ItemLoader.ts @@ -0,0 +1,33 @@ +import * as fs from "node:fs"; +import {StoreComponent} from "../StoreComponent"; +import {ModelComponentType} from "../../../src/app/project/game-model/ModelComponentType"; +import {FileUtils} from "../FileUtils"; + +export class ItemLoader { + private itemDir: string + + + constructor(itemDir: string) { + this.itemDir = itemDir; + } + + loadItems() { + const itemFiles = FileUtils.listFilesInDirectory(this.itemDir); + const loadedItems :StoreComponent[] = [] + itemFiles.forEach(itemFile => { + const loadedItem = this.loadItem(itemFile); + if(loadedItem != undefined) { + loadedItems.push(loadedItem); + } + }) + + return loadedItems; + } + + private loadItem(itemFile: string) { + if(itemFile.endsWith(".json")) { + const itemData = fs.readFileSync(itemFile, 'utf-8'); + return new StoreComponent(itemData, itemFile, ModelComponentType.ITEM) + } + } +} diff --git a/app/storage/storing/ItemStorage.js b/app/storage/storing/ItemStorage.js new file mode 100644 index 0000000..00aa1db --- /dev/null +++ b/app/storage/storing/ItemStorage.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ItemStorage = void 0; +const FileUtils_1 = require("../FileUtils"); +const path = require("node:path"); +const fs = require("node:fs"); +class ItemStorage { + constructor(itemDir) { + this.itemDir = itemDir; + FileUtils_1.FileUtils.prepareDirectoryFroWriting(this.itemDir); + } + storeItem(storedItems) { + this.persistDeletedItems(storedItems); + storedItems.forEach(item => this.storeSingleItem(item)); + } + persistDeletedItems(existingItems) { + const itemFiles = FileUtils_1.FileUtils.listFilesInDirectory(this.itemDir); + itemFiles.forEach(itemFile => { + const itemFileName = path.parse(path.basename(itemFile)).name; + if (existingItems.find(item => item.fileName === itemFileName) == undefined) { + fs.unlinkSync(itemFile); + } + }); + } + storeSingleItem(item) { + const completeItemFile = path.join(this.itemDir, item.fileName + ".json"); + fs.writeFileSync(completeItemFile, item.jsonString, 'utf-8'); + } +} +exports.ItemStorage = ItemStorage; +//# sourceMappingURL=ItemStorage.js.map \ No newline at end of file diff --git a/app/storage/storing/ItemStorage.ts b/app/storage/storing/ItemStorage.ts new file mode 100644 index 0000000..6f8266b --- /dev/null +++ b/app/storage/storing/ItemStorage.ts @@ -0,0 +1,33 @@ +import {FileUtils} from "../FileUtils"; +import {StoreComponent} from "../StoreComponent"; +import * as path from "node:path"; +import * as fs from "node:fs"; + +export class ItemStorage { + private itemDir: string + + constructor(itemDir: string) { + this.itemDir = itemDir; + FileUtils.prepareDirectoryFroWriting(this.itemDir); + } + + storeItem(storedItems: StoreComponent[]) { + this.persistDeletedItems(storedItems); + storedItems.forEach(item => this.storeSingleItem(item)) + } + + private persistDeletedItems(existingItems: StoreComponent[]) { + const itemFiles = FileUtils.listFilesInDirectory(this.itemDir); + itemFiles.forEach(itemFile => { + const itemFileName = path.parse(path.basename(itemFile)).name + if(existingItems.find(item => item.fileName === itemFileName) == undefined) { + fs.unlinkSync(itemFile) + } + }) + } + + private storeSingleItem(item: StoreComponent) { + const completeItemFile = path.join(this.itemDir, item.fileName + ".json"); + fs.writeFileSync(completeItemFile, item.jsonString, 'utf-8') + } +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 0626929..83a3954 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,11 +1,13 @@
+ (click)="openScriptAccountsOverview()">analytics +
@@ -23,11 +25,13 @@ +
+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3ad2831..64992c3 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -27,6 +27,8 @@ import {CharacterParser} from "./project/parser/characterParser/CharacterParser" import {TemplateType} from "./project/game-model/templates/TemplateType"; import {TemplateTypeUtilities} from "./project/game-model/templates/TemplateTypeUtilities"; import {SimpleTemplateGamesystem} from "./project/game-model/templates/simpleGamesystem/SimpleTemplateGamesystem"; +import {ItemSerializer} from "./project/serializer/ItemSerializer"; +import {ItemParser} from "./project/parser/ItemParser"; @Component({ selector: 'app-root', @@ -223,6 +225,8 @@ export class AppComponent implements OnInit{ const characterParser = new CharacterParser(characterTemplateSystems, characterRelationTemplateSystems, gameModel.scriptAccounts); gameModel.characters = characterParser.parseCharacters(storedGameModel.storedCharacters) + gameModel.inventoryItems = ItemParser.parseItems(storedGameModel.storedItems) + this.gameModel = gameModel; } @@ -231,7 +235,11 @@ export class AppComponent implements OnInit{ const storedScriptAccounts = ScriptAccountSerializer.serializeScriptAccounts(this.gameModel.scriptAccounts) const storedGamesystems: StoreComponent[] = GamesystemSerializer.serializeGamesystems(this.gameModel.gamesystems) const storedCharacters: StoreComponent[] = CharacterSerializer.serializeCharacters(this.gameModel.characters) - const storeModel = new StoredGameModel(this.gameModel.gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters) + const storedItems: StoreComponent[] = ItemSerializer.serializeItems(this.gameModel.inventoryItems); + + console.log(this.gameModel.inventoryItems) + const storeModel = new StoredGameModel(this.gameModel.gameModelName, storedScriptAccounts, + storedGamesystems, storedCharacters, storedItems) if(this.electronService.isElectron) { this.electronService.ipcRenderer.send('save-model', storeModel) @@ -254,6 +262,11 @@ export class AppComponent implements OnInit{ this.drawer!.open() } + openContentOverview(contentType: ModelComponentType) { + this.openContent = contentType; + this.drawer!.open(); + } + protected readonly ModelComponentType = ModelComponentType; closeContentOverview() { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 34970f6..a3bac22 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -61,7 +61,7 @@ import { ProductStateEditorComponent } from "./editor/gamesystem-editor/state-editor/product-state-editor/product-state-editor.component"; import {MatTooltip} from "@angular/material/tooltip"; -import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card"; +import {MatCard, MatCardActions, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card"; import { ScriptaccountActionEditorComponent } from "./editor/gamesystem-editor/transition-editor/scriptaccount-action-editor/scriptaccount-action-editor.component"; @@ -82,6 +82,13 @@ import { import { StateInitialCellComponent } from "./editor/gamesystem-editor/state-editor/simple-state-editor/state-initial-cell/state-initial-cell.component"; +import { + InventoryItemOverviewComponent +} from "./side-overviews/inventory-item-overview/inventory-item-overview.component"; +import {InventoryItemEditorComponent} from "./editor/inventory-item-editor/inventory-item-editor.component"; +import { + ItemPropertyEditorComponent +} from "./editor/inventory-item-editor/item-property-editor/item-property-editor.component"; // AoT requires an exported function for factories const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json'); @@ -107,71 +114,75 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl CharacterOverviewComponent, CharacterEditorComponent, TemplateSpecificatorComponent, - StateInitialCellComponent + StateInitialCellComponent, + InventoryItemOverviewComponent, + InventoryItemEditorComponent, + ItemPropertyEditorComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpClientModule, + CoreModule, + SharedModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: httpLoaderFactory, + deps: [HttpClient] + } + }), + BrowserAnimationsModule, + MatIcon, + MatToolbar, + MatButton, + MatFormField, + MatInput, + MatDrawerContainer, + MatDrawer, + MatIconButton, + MatMenuTrigger, + MatMenu, + MatMenuItem, + MatListItem, + MatActionList, + MatTabGroup, + MatTab, + MatTabLabel, + MatLabel, + MatFormField, + ReactiveFormsModule, + MatError, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatMiniFabButton, + MatTreeModule, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCellDef, + MatCell, + MatHeaderRow, + MatRow, + MatHeaderRowDef, + MatRowDef, + MatCheckbox, + MatSelect, + MatOption, + MatHint, + MatTooltip, + MatCard, + MatCardContent, + MatCardHeader, + MatAccordion, + MatExpansionPanel, + MatExpansionPanelTitle, + MatCardTitle, + MatExpansionPanelHeader, + MatCardActions, ], - imports: [ - BrowserModule, - FormsModule, - HttpClientModule, - CoreModule, - SharedModule, - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: httpLoaderFactory, - deps: [HttpClient] - } - }), - BrowserAnimationsModule, - MatIcon, - MatToolbar, - MatButton, - MatFormField, - MatInput, - MatDrawerContainer, - MatDrawer, - MatIconButton, - MatMenuTrigger, - MatMenu, - MatMenuItem, - MatListItem, - MatActionList, - MatTabGroup, - MatTab, - MatTabLabel, - MatLabel, - MatFormField, - ReactiveFormsModule, - MatError, - MatDialogTitle, - MatDialogContent, - MatDialogActions, - MatMiniFabButton, - MatTreeModule, - MatTable, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatCellDef, - MatCell, - MatHeaderRow, - MatRow, - MatHeaderRowDef, - MatRowDef, - MatCheckbox, - MatSelect, - MatOption, - MatHint, - MatTooltip, - MatCard, - MatCardContent, - MatCardHeader, - MatAccordion, - MatExpansionPanel, - MatExpansionPanelTitle, - MatCardTitle, - MatExpansionPanelHeader - ], providers: [], bootstrap: [AppComponent] }) diff --git a/src/app/editor/character-editor/character-editor.component.ts b/src/app/editor/character-editor/character-editor.component.ts index 9c1a072..291f361 100644 --- a/src/app/editor/character-editor/character-editor.component.ts +++ b/src/app/editor/character-editor/character-editor.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {Component, Input, OnInit} from '@angular/core'; import {Character} from "../../project/game-model/characters/Character"; import {GameModel} from "../../project/game-model/GameModel"; import {MatDialog} from "@angular/material/dialog"; diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 23be637..e856a70 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -16,9 +16,11 @@ [scriptAccounts]="gameModel!.scriptAccounts"> - + [gameModel]="gameModel!"> + + diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index 50f44b9..b69cdbf 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -7,6 +7,7 @@ import {State} from "../project/game-model/gamesystems/states/State"; import {Transition} from "../project/game-model/gamesystems/transitions/Transition"; import {ModelComponentType} from "../project/game-model/ModelComponentType"; import {Character} from "../project/game-model/characters/Character"; +import {Item} from "../project/game-model/inventory/Item"; @Component({ @@ -27,6 +28,7 @@ export class EditorComponent { } else { this.activeTab = this.gameModelComponents.findIndex(component => component.componentName === gameModelComponent.componentName); } + console.log(gameModelComponent) } closeGameModelComponent(gameModelComponent: ModelComponent) { @@ -57,4 +59,11 @@ export class EditorComponent { return modelComponent as Character return undefined; } + + convertModelComponentToItem(modelComponent: ModelComponent) { + if(modelComponent instanceof Item) { + return modelComponent as Item + } + return undefined + } } diff --git a/src/app/editor/inventory-item-editor/inventory-item-editor.component.html b/src/app/editor/inventory-item-editor/inventory-item-editor.component.html new file mode 100644 index 0000000..d326add --- /dev/null +++ b/src/app/editor/inventory-item-editor/inventory-item-editor.component.html @@ -0,0 +1,74 @@ + + + Item Qualtities + + + + + + {{quality.quality_step}} + + + + + + + + + + Item Characteristics + + + + + + + + + Item Quality Characteristics + + + + + + + + + + + + + + + + + + + + + + + + +
Name + {{itemProperty.propertyName}} + + Name + + + Description + {{itemProperty.propertyDescription}} + + Name + + + + + + + + + +
+
+
diff --git a/src/app/editor/inventory-item-editor/inventory-item-editor.component.scss b/src/app/editor/inventory-item-editor/inventory-item-editor.component.scss new file mode 100644 index 0000000..8830c59 --- /dev/null +++ b/src/app/editor/inventory-item-editor/inventory-item-editor.component.scss @@ -0,0 +1,7 @@ +table { + width: 100%; +} + +.mat-column-edit, .mat-column-delete { + width: 32px; +} diff --git a/src/app/editor/inventory-item-editor/inventory-item-editor.component.spec.ts b/src/app/editor/inventory-item-editor/inventory-item-editor.component.spec.ts new file mode 100644 index 0000000..f06b796 --- /dev/null +++ b/src/app/editor/inventory-item-editor/inventory-item-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { InventoryItemEditorComponent } from './inventory-item-editor.component'; + +describe('InventoryItemEditorComponent', () => { + let component: InventoryItemEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [InventoryItemEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(InventoryItemEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/inventory-item-editor/inventory-item-editor.component.ts b/src/app/editor/inventory-item-editor/inventory-item-editor.component.ts new file mode 100644 index 0000000..68d0366 --- /dev/null +++ b/src/app/editor/inventory-item-editor/inventory-item-editor.component.ts @@ -0,0 +1,58 @@ +import {Component, ElementRef, Input, OnInit, ViewChildren} from '@angular/core'; +import {Character} from "../../project/game-model/characters/Character"; +import {GameModel} from "../../project/game-model/GameModel"; +import {Item} from "../../project/game-model/inventory/Item"; +import {MatCard, MatCardContent, MatCardHeader} from "@angular/material/card"; +import {ItemPropertyDescription} from "../../project/game-model/inventory/ItemPropertyDescription"; +import {ItemPropertyEditorComponent} from "./item-property-editor/item-property-editor.component"; +import {MatTableDataSource} from "@angular/material/table"; + +@Component({ + selector: 'app-inventory-item-editor', + templateUrl: './inventory-item-editor.component.html', + styleUrl: './inventory-item-editor.component.scss' +}) +export class InventoryItemEditorComponent implements OnInit{ + + @Input() item: Item | undefined; + @Input() gameModel: GameModel | undefined; + @ViewChildren('perQualityPropertyEditors') perQualityPropertyEditors: ItemPropertyEditorComponent[] = []; + + displayedColumns: string[] = ['name', 'description', 'edit', 'delete'] + editedProperty: ItemPropertyDescription | undefined + + datasource: MatTableDataSource = new MatTableDataSource() + + ngOnInit() { + this.datasource.data = this.item!.perQualityProperties + } + + deletePerQualityProperty(itemProperty: ItemPropertyDescription) { + this.item!.removePerQualityProperty(itemProperty); + this.datasource.data = this.item!.perQualityProperties + this.perQualityPropertyEditors.forEach(component => component.updatedDisplayedData()) + } + + editPerQualityProperty(itemProperty: ItemPropertyDescription) { + this.editedProperty = itemProperty + } + + finishEditing() { + if(this.editedProperty!.propertyName.length > 0) { + this.item!.editPerQualityProperty(this.editedProperty!); + + this.editedProperty = undefined; + this.perQualityPropertyEditors.forEach(component => component.updatedDisplayedData()) + } + } + + addQualityProperty() { + const qualityDescription = new ItemPropertyDescription("New Property", "") + this.item!.addPerQualityProperty(qualityDescription); + this.datasource.data = this.item!.perQualityProperties + this.editedProperty = qualityDescription; + + this.perQualityPropertyEditors.forEach(component => component.updatedDisplayedData()) + + } +} diff --git a/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.html b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.html new file mode 100644 index 0000000..733f829 --- /dev/null +++ b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name + {{itemProperty.propertyName}} + + Name + + + +
+

{{element.propertyDescription}}

+ + Description + + +
+
Value +

{{itemProperty.property}}

+ + Value + + +
+ + + + + + + + +
diff --git a/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.scss b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.scss new file mode 100644 index 0000000..f4b8648 --- /dev/null +++ b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.scss @@ -0,0 +1,57 @@ +table { + width: 100%; +} + +tr.example-detail-row { + height: 0; +} + +tr.example-element-row:not(.example-expanded-row):hover { + background: #545456 +} + +tr.example-element-row:not(.example-expanded-row):active { + background: #545456; +} + +.example-element-row td { + border-bottom-width: 0; +} +.example-element-diagram { + min-width: 80px; + border: 2px solid black; + padding: 8px; + font-weight: lighter; + margin: 8px 0; + height: 104px; +} + +.example-element-symbol { + font-weight: bold; + font-size: 40px; + line-height: normal; +} + +.example-element-description { + padding: 16px; +} + +.example-element-description-attribution { + opacity: 0.5; +} + +.mat-column-edit, .mat-column-delete, .mat-column-expand { + width: 32px; +} + +.long-form { + width: 100%; +} + +.mat-error { + color: red; +} + +.warning-icon { + margin-right: 5px; +} diff --git a/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.spec.ts b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.spec.ts new file mode 100644 index 0000000..7343da8 --- /dev/null +++ b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemPropertyEditorComponent } from './item-property-editor.component'; + +describe('ItemPropertyEditorComponent', () => { + let component: ItemPropertyEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ItemPropertyEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemPropertyEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.ts b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.ts new file mode 100644 index 0000000..98909aa --- /dev/null +++ b/src/app/editor/inventory-item-editor/item-property-editor/item-property-editor.component.ts @@ -0,0 +1,82 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Item} from "../../../project/game-model/inventory/Item"; +import {MatTableDataSource} from "@angular/material/table"; +import {ItemProperty} from "../../../project/game-model/inventory/ItemProperty"; +import {animate, state, style, transition, trigger} from "@angular/animations"; +import {MatSnackBar} from "@angular/material/snack-bar"; +import {ItemQuality} from "../../../project/game-model/inventory/ItemQuality"; + +@Component({ + selector: 'app-item-property-editor', + templateUrl: './item-property-editor.component.html', + styleUrl: './item-property-editor.component.scss', + animations: [ + trigger('detailExpand', [ + state('collapsed,void', style({height: '0px', minHeight: '0'})), + state('expanded', style({height: '*'})), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ], +}) +export class ItemPropertyEditorComponent implements OnInit{ + + @Input() item: Item | undefined + @Input() quality: ItemQuality | undefined + editedItemProperty: ItemProperty | undefined + expandedElement: ItemProperty | undefined + + displayedColumns: string[] = ['name', 'property', 'edit', 'delete'] + columnsToDisplayWithExpand = [...this.displayedColumns, 'expand']; + + datasource: MatTableDataSource = new MatTableDataSource(); + + constructor(private snackbar: MatSnackBar) { + } + + ngOnInit() { + this.updatedDisplayedData() + } + + deleteItemProperty(itemProperty: ItemProperty) { + if(this.quality == undefined) { + this.item!.itemProperties = this.item!.itemProperties.filter(property => property.propertyName !== itemProperty.propertyName) + this.datasource.data = this.item!.itemProperties + } else { + this.quality.quality_propertes = this.quality.quality_propertes.filter(property => property.propertyName !== itemProperty.propertyName) + this.datasource.data = this.quality.quality_propertes; + } + + + } + + editItemProperty(itemProperty: ItemProperty) { + this.editedItemProperty = itemProperty + } + + finishEditing() { + if(this.editedItemProperty!.propertyName.length < 1) { + this.snackbar.open("PropertyName cannout be empty", "", {duration: 2000}); + } else { + this.editedItemProperty = undefined + } + } + + addItemProperty() { + if(this.quality == undefined) { + const itemProperty = new ItemProperty("New Property", "", 0); + this.item!.itemProperties.push(itemProperty); + this.datasource.data = this.item!.itemProperties; + this.editedItemProperty = itemProperty; + } + } + + updatedDisplayedData() { + if(this.quality != undefined) { + this.datasource.data = this.quality!.quality_propertes + this.displayedColumns = ['name', 'property', 'edit'] + this.columnsToDisplayWithExpand = [...this.displayedColumns, 'expand']; + } else { + this.datasource.data = this.item!.itemProperties + } + } +} diff --git a/src/app/project/game-model/GameModel.ts b/src/app/project/game-model/GameModel.ts index 295b6bb..4ba59a8 100644 --- a/src/app/project/game-model/GameModel.ts +++ b/src/app/project/game-model/GameModel.ts @@ -11,6 +11,7 @@ import {SimpleTemplateGamesystem} from "./templates/simpleGamesystem/SimpleTempl import {ProductTemplateSystem} from "./templates/productGamesystem/ProductTemplateSystem"; import {ProductTemplateCreator} from "./templates/productGamesystem/ProductTemplateCreator"; import {CharacterRelation} from "./characters/CharacterRelation"; +import {Item} from "./inventory/Item"; export class GameModel { gameModelName: string @@ -18,6 +19,7 @@ export class GameModel { gamesystems: Gamesystem[] = []; scriptAccounts: ScriptAccount[] = []; characters: Character[] = [] + inventoryItems: Item[] = [] constructor(gameModelName: string) { this.gameModelName = gameModelName; @@ -101,7 +103,12 @@ export class GameModel { return simpleGamesystem; } - + createInventoryItem(itemName: string) { + if(itemName != undefined) { + const item = new Item(itemName, "", ModelComponentType.ITEM); + this.inventoryItems.push(item); + } + } createGamesystem(gamesystemName: string, parentGamesystemName: string | undefined, templateType: TemplateType | undefined) { if(gamesystemName != undefined && this.findGamesystem(gamesystemName) == undefined) { @@ -156,6 +163,10 @@ export class GameModel { } } + removeItem(item: Item) { + this.inventoryItems = this.inventoryItems.filter(i => i.componentName === item.componentName) + } + findGamesystem(gamesystemName: string) { const gamesystemQueue : Gamesystem, Transition>[] = []; this.gamesystems.forEach(gamesystem => gamesystemQueue.push(gamesystem)); diff --git a/src/app/project/game-model/ModelComponentType.ts b/src/app/project/game-model/ModelComponentType.ts index 14eaf8b..4baebb9 100644 --- a/src/app/project/game-model/ModelComponentType.ts +++ b/src/app/project/game-model/ModelComponentType.ts @@ -1,6 +1,6 @@ export enum ModelComponentType { SCRIPTACCOUNT, GAMESYTEM, - CHARACTER - + CHARACTER, + ITEM } diff --git a/src/app/project/game-model/ModelComponentTypeUtillities.ts b/src/app/project/game-model/ModelComponentTypeUtillities.ts index aa736fd..a2bdc40 100644 --- a/src/app/project/game-model/ModelComponentTypeUtillities.ts +++ b/src/app/project/game-model/ModelComponentTypeUtillities.ts @@ -5,7 +5,8 @@ export class ModelComponentTypeUtillities { switch (modelComponentType) { case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccounts"; case ModelComponentType.GAMESYTEM: return "Gamesystems"; - case ModelComponentType.CHARACTER: return "Characters" + case ModelComponentType.CHARACTER: return "Characters"; + case ModelComponentType.ITEM: return "Items"; default: return "Undefined"; } } @@ -15,6 +16,7 @@ export class ModelComponentTypeUtillities { case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccount"; case ModelComponentType.GAMESYTEM: return "Gamesystem"; case ModelComponentType.CHARACTER: return "Character" + case ModelComponentType.ITEM: return "Item" default: return "Undefined"; } } @@ -24,6 +26,7 @@ export class ModelComponentTypeUtillities { case "gamesystem": return ModelComponentType.GAMESYTEM; case "scriptaccount": return ModelComponentType.SCRIPTACCOUNT; case "character": return ModelComponentType.CHARACTER + case "item": return ModelComponentType.ITEM } } } diff --git a/src/app/project/game-model/inventory/Item.ts b/src/app/project/game-model/inventory/Item.ts new file mode 100644 index 0000000..13f8a35 --- /dev/null +++ b/src/app/project/game-model/inventory/Item.ts @@ -0,0 +1,44 @@ +import {ItemProperty} from "./ItemProperty"; +import {ItemQuality} from "./ItemQuality"; +import {ModelComponent} from "../ModelComponent"; +import {ModelComponentType} from "../ModelComponentType"; +import {ItemPropertyDescription} from "./ItemPropertyDescription"; + +export class Item extends ModelComponent { + + possible_qualities: ItemQuality[] = [] + itemProperties: ItemProperty[] = [] + + perQualityProperties: ItemPropertyDescription[] = [] + + constructor(componentName: string, componentDescription: string, type: ModelComponentType) { + super(componentName, componentDescription, type); + this.itemProperties.push(new ItemProperty("Weight", "Some Weights", 10)) + this.possible_qualities.push(new ItemQuality(0.25)) + this.possible_qualities.push(new ItemQuality(0.50)) + this.possible_qualities.push(new ItemQuality(0.75)) + this.possible_qualities.push(new ItemQuality(1.00)) + + this.addPerQualityProperty(new ItemPropertyDescription("Price", "Price to buy item")) + } + + removePerQualityProperty(qualityProperty: ItemPropertyDescription) { + this.perQualityProperties = this.perQualityProperties.filter(perQualityProperty => perQualityProperty !== qualityProperty); + this.possible_qualities.forEach(quality => { + quality.removeQualityProperty(qualityProperty.propertyName); + }) + } + + addPerQualityProperty(qualityProperty: ItemPropertyDescription) { + if(this.perQualityProperties.find(property => property.propertyName === qualityProperty.propertyName) == undefined) { + this.perQualityProperties.push(qualityProperty); + this.possible_qualities.forEach(quality => quality.addQualityProperty(qualityProperty)) + } + } + + editPerQualityProperty(qualityProperty: ItemPropertyDescription) { + this.possible_qualities.forEach(quality => { + quality.editQualityProperty(qualityProperty, this.perQualityProperties.map(property => property.propertyName)) + }) + } +} diff --git a/src/app/project/game-model/inventory/ItemProperty.ts b/src/app/project/game-model/inventory/ItemProperty.ts new file mode 100644 index 0000000..e710c2d --- /dev/null +++ b/src/app/project/game-model/inventory/ItemProperty.ts @@ -0,0 +1,12 @@ +export class ItemProperty { + propertyName: string + propertyDescription: string + property: number + + + constructor(propertyName: string, propertyDescription: string, property: number) { + this.propertyName = propertyName; + this.propertyDescription = propertyDescription; + this.property = property; + } +} diff --git a/src/app/project/game-model/inventory/ItemPropertyDescription.ts b/src/app/project/game-model/inventory/ItemPropertyDescription.ts new file mode 100644 index 0000000..174cf31 --- /dev/null +++ b/src/app/project/game-model/inventory/ItemPropertyDescription.ts @@ -0,0 +1,10 @@ +export class ItemPropertyDescription { + propertyName: string; + propertyDescription: string; + + + constructor(propertyName: string, propertyDescription: string) { + this.propertyName = propertyName; + this.propertyDescription = propertyDescription; + } +} diff --git a/src/app/project/game-model/inventory/ItemQuality.ts b/src/app/project/game-model/inventory/ItemQuality.ts new file mode 100644 index 0000000..e31ad63 --- /dev/null +++ b/src/app/project/game-model/inventory/ItemQuality.ts @@ -0,0 +1,30 @@ +import {ItemProperty} from "./ItemProperty"; +import {ItemPropertyDescription} from "./ItemPropertyDescription"; + +export class ItemQuality { + quality_step: number + quality_propertes: ItemProperty[] = [] + + + constructor(quality_step: number) { + this.quality_step = quality_step; + } + + removeQualityProperty(propertyName: string) { + this.quality_propertes = this.quality_propertes.filter(qualityProperty => qualityProperty.propertyName !== propertyName); + } + + addQualityProperty(qualityProperty: ItemPropertyDescription) { + this.quality_propertes.push(new ItemProperty(qualityProperty.propertyName, qualityProperty.propertyDescription, 0)); + } + + editQualityProperty(qualityProperty: ItemPropertyDescription, knownProperties: string[]) { + const affectedProperty = this.quality_propertes.find(property => !knownProperties.includes(property.propertyName) ) + if(affectedProperty != undefined) { + affectedProperty!.propertyName = qualityProperty.propertyName; + affectedProperty!.propertyDescription = qualityProperty.propertyDescription; + } else { + console.log("Property was not found") + } + } +} diff --git a/src/app/project/parser/ItemParser.ts b/src/app/project/parser/ItemParser.ts new file mode 100644 index 0000000..f6f1bf6 --- /dev/null +++ b/src/app/project/parser/ItemParser.ts @@ -0,0 +1,85 @@ +import {StoreComponent} from "../../../../app/storage/StoreComponent"; +import {Item} from "../game-model/inventory/Item"; +import {ItemQuality} from "../game-model/inventory/ItemQuality"; +import {ItemProperty} from "../game-model/inventory/ItemProperty"; +import {ItemPropertyDescription} from "../game-model/inventory/ItemPropertyDescription"; +import {ModelComponentType} from "../game-model/ModelComponentType"; + +export class ItemParser { + + public static parseItems(items: StoreComponent[]): Item[] { + const parsedItems: Item[] = [] + items.forEach(item => parsedItems.push(this.parseSingleItem(JSON.parse(item.jsonString)))); + return parsedItems; + } + + private static parseSingleItem(itemData: any): Item { + const componentName = itemData.componentName; + const componentDescription = itemData.componentDescription; + + const perQualityProperties = this.parseQualityPropertyReferences(itemData.perQualityProperties); + const qualties = this.parseQualities(itemData.possible_qualities, perQualityProperties) + const itemProperties = this.parseItemProperties(itemData.itemProperties) + + const item = new Item(componentName, componentDescription, ModelComponentType.ITEM); + item.possible_qualities = qualties; + item.itemProperties = itemProperties; + item.perQualityProperties = perQualityProperties; + + return item; + } + + private static parseItemProperties(propertyData: any): ItemProperty[] { + const itemProperties : ItemProperty[] = [] + for(let i=0; i property.propertyName === propertyName); + } + + private static parseQualityPropertyReferences(qualityPropertyData: any): ItemPropertyDescription[] { + const result: ItemPropertyDescription[] = [] + for(let i=0; i storedItems.push(this.serializeSingleItem(item))) + return storedItems; + } + + private static serializeSingleItem(item: Item): StoreComponent { + const fileName = item.componentName; + const componentType = item.type; + const jsonString = JSON.stringify(item,(key, value) => { + if(key === 'perQualityProperties') { + return value; + } else if(key == 'quality_propertes') { + return value.map((prop: ItemProperty) => ({ + ...prop, + propertyDescription: undefined + })); + } + + if(key === 'unsaved' || key === 'type') { + return undefined; + } else { + return value; + } + }, SerializeConstants.JSON_INDENT) + + return new StoreComponent(jsonString, fileName, componentType); + } +} diff --git a/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.html b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.html new file mode 100644 index 0000000..16c4e63 --- /dev/null +++ b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.html @@ -0,0 +1,8 @@ + + + inventory_2{{item.componentName}} + + diff --git a/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.scss b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.scss new file mode 100644 index 0000000..41ac5cd --- /dev/null +++ b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.scss @@ -0,0 +1,14 @@ +.item { + min-height: 1.8em !important; + height: 1.8em !important; +} + +.icon { + margin-right: 10px; + color: #ccffff; + align-content: baseline; +} + +.selected-item { + background-color: #8696b6; +} diff --git a/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.spec.ts b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.spec.ts new file mode 100644 index 0000000..4681b34 --- /dev/null +++ b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { InventoryItemOverviewComponent } from './inventory-item-overview.component'; + +describe('InventoryItemOverviewComponent', () => { + let component: InventoryItemOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [InventoryItemOverviewComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(InventoryItemOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.ts b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.ts new file mode 100644 index 0000000..f1b2cf0 --- /dev/null +++ b/src/app/side-overviews/inventory-item-overview/inventory-item-overview.component.ts @@ -0,0 +1,34 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {GameModel} from "../../project/game-model/GameModel"; +import {Item} from "../../project/game-model/inventory/Item"; +import {MatActionList, MatListItem} from "@angular/material/list"; +import {MatIcon} from "@angular/material/icon"; +import {NgForOf} from "@angular/common"; +import {ScriptAccount} from "../../project/game-model/scriptAccounts/ScriptAccount"; + +@Component({ + selector: 'app-inventory-item-overview', + templateUrl: './inventory-item-overview.component.html', + styleUrl: './inventory-item-overview.component.scss' +}) +export class InventoryItemOverviewComponent { + + @Input() gameModel: GameModel | undefined; + @Output() openItemEditor = new EventEmitter(); + + + selectedItem: Item | undefined + + onOpenItemEditor(item: Item) { + this.openItemEditor.emit(item) + } + + + selectItem(item: Item) { + if(this.selectedItem != undefined && this.selectedItem!.componentName === item.componentName) { + this.selectedItem = undefined + } else { + this.selectedItem = item + } + } +} diff --git a/src/app/side-overviews/script-account-overview/script-account-overview.component.html b/src/app/side-overviews/script-account-overview/script-account-overview.component.html index 797174b..8781cb1 100644 --- a/src/app/side-overviews/script-account-overview/script-account-overview.component.html +++ b/src/app/side-overviews/script-account-overview/script-account-overview.component.html @@ -3,6 +3,6 @@ (dblclick)="onOpenScriptAccount(scriptAccount)" (click)="selectScriptAccount(scriptAccount)" [ngClass]="selectedScriptAccount === scriptAccount ?'selected-item':''" (contextmenu)="selectScriptAccount(scriptAccount)"> - inventory_2{{scriptAccount.componentName}} + analytics{{scriptAccount.componentName}} diff --git a/testModel/items/Item 1.json b/testModel/items/Item 1.json new file mode 100644 index 0000000..2316aa2 --- /dev/null +++ b/testModel/items/Item 1.json @@ -0,0 +1,55 @@ +{ + "componentName": "Item 1", + "componentDescription": "", + "possible_qualities": [ + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.25 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.5 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.75 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 1 + } + ], + "itemProperties": [ + { + "propertyName": "Weight", + "propertyDescription": "Some Weights", + "property": 10 + } + ], + "perQualityProperties": [ + { + "propertyName": "Price", + "propertyDescription": "Price to buy item" + } + ] +} \ No newline at end of file diff --git a/testModel/items/Item 2.json b/testModel/items/Item 2.json new file mode 100644 index 0000000..1e3bc67 --- /dev/null +++ b/testModel/items/Item 2.json @@ -0,0 +1,55 @@ +{ + "componentName": "Item 2", + "componentDescription": "", + "possible_qualities": [ + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.25 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.5 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 0.75 + }, + { + "quality_propertes": [ + { + "propertyName": "Price", + "property": 0 + } + ], + "quality_step": 1 + } + ], + "itemProperties": [ + { + "propertyName": "Weight", + "propertyDescription": "Some Weights", + "property": 10 + } + ], + "perQualityProperties": [ + { + "propertyName": "Price", + "propertyDescription": "Price to buy item" + } + ] +} \ No newline at end of file