// Objects returns an array of all used objects. func (level *Level) Objects() []model.LevelObject { level.mutex.Lock() defer level.mutex.Unlock() var result []model.LevelObject for index, rawEntry := range level.objectList { if rawEntry.IsInUse() { entry := model.LevelObject{ Identifiable: model.Identifiable{ID: fmt.Sprintf("%d", index)}, Class: int(rawEntry.Class), Subclass: int(rawEntry.Subclass), Type: int(rawEntry.Type)} entry.BaseProperties.TileX = int(rawEntry.X >> 8) entry.BaseProperties.FineX = int(rawEntry.X & 0xFF) entry.BaseProperties.TileY = int(rawEntry.Y >> 8) entry.BaseProperties.FineY = int(rawEntry.Y & 0xFF) entry.BaseProperties.Z = int(rawEntry.Z) entry.Hacking.Unknown0013 = bytesToIntArray(rawEntry.Unknown0013[:]) entry.Hacking.Unknown0017 = bytesToIntArray(rawEntry.Unknown0017[:]) meta := data.LevelObjectClassMetaEntry(rawEntry.Class) classStore := level.store.Get(res.ResourceID(4000 + level.id*100 + 10 + entry.Class)) blockData := classStore.BlockData(0) startOffset := meta.EntrySize * int(rawEntry.ClassTableIndex) if (startOffset + meta.EntrySize) > len(blockData) { fmt.Printf("!!!!! class %d meta says %d bytes size, can't reach index %d in blockData %d", int(entry.Class), meta.EntrySize, rawEntry.ClassTableIndex, len(blockData)) } else { entry.Hacking.ClassData = bytesToIntArray(blockData[startOffset+data.LevelObjectPrefixSize : startOffset+meta.EntrySize]) } result = append(result, entry) } } return result }
// AddObject adds a new object at given tile. func (level *Level) AddObject(template *model.LevelObjectTemplate) (createdIndex int, err error) { level.mutex.Lock() defer level.mutex.Unlock() objID := res.MakeObjectID(res.ObjectClass(template.Class), res.ObjectSubclass(template.Subclass), res.ObjectType(template.Type)) classMeta := data.LevelObjectClassMetaEntry(objID.Class) classStore := level.store.Get(res.ResourceID(4000 + level.id*100 + 10 + int(objID.Class))) classTable := logic.DecodeLevelObjectClassTable(classStore.BlockData(0), classMeta.EntrySize) classChain := classTable.AsChain() classIndex, classErr := classChain.AcquireLink() if classErr != nil { err = classErr return } classEntry := classTable.Entry(classIndex) classEntryData := classEntry.Data() for index := 0; index < len(classEntryData); index++ { classEntryData[index] = 0x00 } objectIndex, objectErr := level.objectChain.AcquireLink() if objectErr != nil { classChain.ReleaseLink(classIndex) err = objectErr return } createdIndex = int(objectIndex) locations := []logic.TileLocation{logic.AtTile(uint16(template.TileX), uint16(template.TileY))} crossrefIndex, crossrefErr := level.crossrefList.AddObjectToMap(uint16(objectIndex), level.tileMap, locations) if crossrefErr != nil { classChain.ReleaseLink(classIndex) level.objectChain.ReleaseLink(objectIndex) err = crossrefErr return } crossrefEntry := level.crossrefList.Entry(crossrefIndex) objectEntry := &level.objectList[objectIndex] objectEntry.InUse = 1 objectEntry.Class = objID.Class objectEntry.Subclass = objID.Subclass objectEntry.Type = objID.Type objectEntry.X = data.MapCoordinateOf(byte(template.TileX), byte(template.FineX)) objectEntry.Y = data.MapCoordinateOf(byte(template.TileY), byte(template.FineY)) objectEntry.Z = byte(template.Z) objectEntry.Rot1 = 0 objectEntry.Rot2 = 0 objectEntry.Rot3 = 0 objectEntry.Hitpoints = 1 objectEntry.CrossReferenceTableIndex = uint16(crossrefIndex) crossrefEntry.LevelObjectTableIndex = uint16(objectIndex) objectEntry.ClassTableIndex = uint16(classIndex) classEntry.LevelObjectTableIndex = uint16(objectIndex) classStore.SetBlockData(0, classTable.Encode()) objWriter := bytes.NewBuffer(nil) binary.Write(objWriter, binary.LittleEndian, level.objectList) level.objectListStore.SetBlockData(0, objWriter.Bytes()) level.crossrefListStore.SetBlockData(0, level.crossrefList.Encode()) level.onTileDataChanged() return }