// NewLevel returns a new instance of a Level structure. func NewLevel(store chunk.Store, id int) *Level { baseStoreID := 4000 + id*100 level := &Level{ id: id, store: store, tileMapStore: store.Get(res.ResourceID(baseStoreID + 5)), tileMap: nil, objectListStore: store.Get(res.ResourceID(baseStoreID + 8)), crossrefListStore: store.Get(res.ResourceID(baseStoreID + 9))} level.tileMap = logic.DecodeTileMap(level.tileMapStore.BlockData(0), 64, 64) level.crossrefList = logic.DecodeCrossReferenceList(level.crossrefListStore.BlockData(0)) { blockData := level.objectListStore.BlockData(0) level.objectList = make([]data.LevelObjectEntry, len(blockData)/data.LevelObjectEntrySize) reader := bytes.NewReader(blockData) binary.Read(reader, binary.LittleEndian, &level.objectList) level.objectChain = logic.NewLevelObjectChain(&level.objectList[0], func(index data.LevelObjectChainIndex) logic.LevelObjectChainLink { return &level.objectList[index] }) } return level }
func (suite *ReleaseStoreLibrarySuite) TestChunkStoreIsBackedBySourceIfExisting(c *check.C) { suite.createChunkResource(suite.source, "fromSource.res", func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) store, err := suite.library.ChunkStore("fromSource.res") c.Assert(err, check.IsNil) c.Assert(store, check.NotNil) blockStore := store.Get(res.ResourceID(1)) c.Check(blockStore.BlockCount(), check.Equals, uint16(1)) }
func (textures *Textures) SetProperties(index int, prop model.TextureProperties) { for i := 0; i < model.LanguageCount; i++ { if prop.Name[i] != nil { names := textures.cybstrng[i].Get(res.ResourceID(0x086A)) names.SetBlockData(uint16(index), textures.EncodeString(prop.Name[i])) } if prop.CantBeUsed[i] != nil { cantBeUseds := textures.cybstrng[i].Get(res.ResourceID(0x086B)) cantBeUseds.SetBlockData(uint16(index), textures.EncodeString(prop.CantBeUsed[i])) } } }
func (suite *DynamicChunkStoreSuite) TestGetReturnsBlockFromWrapped(c *check.C) { provider := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) wrappedStore := store.NewProviderBacked(provider, func() {}) store := NewDynamicChunkStore(wrappedStore) holder := store.Get(res.ResourceID(1)) c.Check(holder, check.NotNil) }
func (suite *DynamicChunkStoreSuite) TestDelDeletesFromWrapped(c *check.C) { provider := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) wrappedStore := store.NewProviderBacked(provider, func() {}) store := NewDynamicChunkStore(wrappedStore) store.Del(res.ResourceID(1)) ids := store.IDs() c.Check(len(ids), check.Equals, 0) }
func (textures *Textures) Properties(index int) model.TextureProperties { prop := model.TextureProperties{} for i := 0; i < model.LanguageCount; i++ { names := textures.cybstrng[i].Get(res.ResourceID(0x086A)) cantBeUseds := textures.cybstrng[i].Get(res.ResourceID(0x086B)) prop.Name[i] = textures.DecodeString(names.BlockData(uint16(index))) prop.CantBeUsed[i] = textures.DecodeString(cantBeUseds.BlockData(uint16(index))) } return prop }
// Properties returns the current properties of a specific game object. func (gameObjects *GameObjects) Properties(id res.ObjectID) model.GameObjectProperties { prop := model.GameObjectProperties{} index := objprop.ObjectIDToIndex(gameObjects.desc, id) for i := 0; i < model.LanguageCount; i++ { shortName := gameObjects.cybstrng[i].Get(res.ResourceID(0x086D)) longName := gameObjects.cybstrng[i].Get(res.ResourceID(0x0024)) prop.ShortName[i] = gameObjects.decodeString(shortName.BlockData(uint16(index))) prop.LongName[i] = gameObjects.decodeString(longName.BlockData(uint16(index))) } return prop }
func (suite *DynamicChunkStoreSuite) TestBlockHolderModifiesWrapped(c *check.C) { provider := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) wrappedStore := store.NewProviderBacked(provider, func() {}) store := NewDynamicChunkStore(wrappedStore) data := []byte{0x01, 0x02} holder := store.Get(res.ResourceID(1)) holder.SetBlockData(0, data) c.Check(wrappedStore.Get(res.ResourceID(1)).BlockData(0), check.DeepEquals, data) }
func (suite *DynamicChunkStoreSuite) TestSwapReplacesWrapped(c *check.C) { provider1 := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) provider2 := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(2), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) testStore := NewDynamicChunkStore(store.NewProviderBacked(provider1, func() {})) testStore.Swap(func(oldStore chunk.Store) chunk.Store { return store.NewProviderBacked(provider2, func() {}) }) c.Check(testStore.IDs(), check.DeepEquals, []res.ResourceID{res.ResourceID(2)}) }
func (suite *ReleaseStoreLibrarySuite) TestModifyingChunkSourceSavesNewSink(c *check.C) { suite.createChunkResource(suite.source, "source.res", func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) store, err := suite.library.ChunkStore("source.res") c.Assert(err, check.IsNil) c.Assert(store, check.NotNil) store.Del(res.ResourceID(1)) time.Sleep(100 * time.Millisecond) c.Check(suite.sink.HasResource("source.res"), check.Equals, true) }
func (textures *Textures) Image(index int, size model.TextureSize) (bmp image.Bitmap) { var blockData []byte if size == model.TextureLarge { blockData = textures.images.Get(res.ResourceID(0x03E8 + index)).BlockData(0) } else if size == model.TextureMedium { blockData = textures.images.Get(res.ResourceID(0x02C3 + index)).BlockData(0) } else if size == model.TextureSmall { blockData = textures.images.Get(res.ResourceID(0x004D)).BlockData(uint16(index)) } else if size == model.TextureIcon { blockData = textures.images.Get(res.ResourceID(0x004C)).BlockData(uint16(index)) } bmp, _ = image.Read(bytes.NewReader(blockData)) return }
func (suite *DynamicChunkStoreSuite) TestGetReturnsNilIfWrappedDoesntHaveIt(c *check.C) { provider := suite.createChunkProvider(func(consumer chunk.Consumer) {}) wrappedStore := store.NewProviderBacked(provider, func() {}) store := NewDynamicChunkStore(wrappedStore) holder := store.Get(res.ResourceID(2)) c.Check(holder, check.IsNil) }
func (suite *DynamicChunkStoreSuite) TestBlockHolderModifiesWrappedAfterSwap(c *check.C) { provider1 := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) provider2 := suite.createChunkProvider(func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) testStore := NewDynamicChunkStore(store.NewProviderBacked(provider1, func() {})) holder := testStore.Get(res.ResourceID(1)) wrapped2 := store.NewProviderBacked(provider2, func() {}) testStore.Swap(func(oldStore chunk.Store) chunk.Store { return wrapped2 }) data := []byte{0x01, 0x02} holder.SetBlockData(0, data) c.Check(wrapped2.Get(res.ResourceID(1)).BlockData(0), check.DeepEquals, data) }
// Properties returns the properties of the level. func (level *Level) Properties() (result model.LevelProperties) { blockData := level.store.Get(res.ResourceID(4000 + level.id*100 + 4)).BlockData(0) reader := bytes.NewReader(blockData) var info data.LevelInformation binary.Read(reader, binary.LittleEndian, &info) result.CyberspaceFlag = info.IsCyberspace() result.HeightShift = int(info.HeightShift) return }
// Icon returns the icon image of the specified game object. // It first tries to return the bitmap for the map icon. If that is all transparent, // the function reverts to the object icon. func (gameObjects *GameObjects) Icon(id res.ObjectID) (bmp image.Bitmap) { mapIconBlockData := gameObjects.objart.Get(res.ResourceID(0x0546)).BlockData(uint16(gameObjects.mapIconOffsets[id])) bmp, _ = image.Read(bytes.NewReader(mapIconBlockData)) allZero := true for row := 0; row < int(bmp.ImageHeight()); row++ { for _, b := range bmp.Row(row) { if b != 0x00 { allZero = false } } } if allZero { objIconBlockData := gameObjects.objart.Get(res.ResourceID(0x0546)).BlockData(uint16(gameObjects.objIconOffsets[id])) bmp, _ = image.Read(bytes.NewReader(objIconBlockData)) } return }
// Textures returns the texture identifier used in this level. func (level *Level) Textures() (result []int) { blockData := level.store.Get(res.ResourceID(4000 + level.id*100 + 7)).BlockData(0) reader := bytes.NewReader(blockData) var ids [54]uint16 binary.Read(reader, binary.LittleEndian, &ids) for _, id := range ids { result = append(result, int(id)) } return }
func (suite *ReleaseStoreLibrarySuite) TestChunkStoreReturnsSameInstances(c *check.C) { suite.createChunkResource(suite.source, "source.res", func(consumer chunk.Consumer) { consumer.Consume(res.ResourceID(1), chunk.NewBlockHolder(chunk.BasicChunkType, res.Palette, [][]byte{[]byte{}})) }) store1, err1 := suite.library.ChunkStore("source.res") c.Assert(err1, check.IsNil) c.Assert(store1, check.NotNil) store2, err2 := suite.library.ChunkStore("source.res") c.Assert(err2, check.IsNil) c.Check(store1, check.Equals, store2) }
// SetTextures sets the texture identifier for this level. func (level *Level) SetTextures(newIds []int) { blockStore := level.store.Get(res.ResourceID(4000 + level.id*100 + 7)) var ids [54]uint16 toCopy := len(ids) if len(newIds) < toCopy { toCopy = len(newIds) } for index := 0; index < len(ids); index++ { ids[index] = uint16(newIds[index]) } buffer := bytes.NewBuffer(nil) binary.Write(buffer, binary.LittleEndian, &ids) blockStore.SetBlockData(0, buffer.Bytes()) }
// GET /projects/{project-id}/fonts/{font-id} func (resource *WorkspaceResource) getFont(request *restful.Request, response *restful.Response) { projectID := request.PathParameter("project-id") project, err := resource.ws.Project(projectID) if err == nil { fontID, _ := strconv.ParseInt(request.PathParameter("font-id"), 10, 16) var entity *model.Font entity, err = project.Fonts().Font(res.ResourceID(fontID)) if err == nil { response.WriteEntity(*entity) } else { response.AddHeader("Content-Type", "text/plain") response.WriteErrorString(http.StatusBadRequest, err.Error()) } } else { response.AddHeader("Content-Type", "text/plain") response.WriteErrorString(http.StatusBadRequest, err.Error()) return } }
// 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 }
func (level *Level) readTable(levelBlockID int, value interface{}) { blockData := level.store.Get(res.ResourceID(4000 + level.id*100 + levelBlockID)).BlockData(0) reader := bytes.NewReader(blockData) binary.Read(reader, binary.LittleEndian, value) }
// 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 }
func (palettes *Palettes) GamePalette() (color.Palette, error) { blockData := palettes.gamepal.Get(res.ResourceID(0x02BC)).BlockData(0) return image.LoadPalette(bytes.NewReader(blockData)) }
// HasLevel returns true when given level ID (0..15) refers to a valid level. func (archive *Archive) HasLevel(id int) bool { return archive.store.Get(res.ResourceID(4000+id*100+4)) != nil }