func (level *Level) getTileType(x, y int) data.TileType { tileType := data.Solid if (x >= 0) && (x < 64) && (y >= 0) && (y < 64) { entry := level.tileMap.Entry(logic.AtTile(uint16(x), uint16(y))) tileType = entry.Type } return tileType }
// SetTileProperties sets the properties of a specific tile. func (level *Level) SetTileProperties(x, y int, properties model.TileProperties) { level.mutex.Lock() defer level.mutex.Unlock() entry := level.tileMap.Entry(logic.AtTile(uint16(x), uint16(y))) flags := uint32(entry.Flags) if properties.Type != nil { entry.Type = tileType(*properties.Type) } if properties.FloorHeight != nil { entry.Floor = (entry.Floor & 0xE0) | (byte(*properties.FloorHeight) & 0x1F) } if properties.CeilingHeight != nil { entry.Ceiling = (entry.Ceiling & 0xE0) | (byte(*properties.CeilingHeight) & 0x1F) } if properties.SlopeHeight != nil { entry.SlopeHeight = byte(*properties.SlopeHeight) } if properties.SlopeControl != nil { flags = (flags & ^uint32(0x00000C00)) | (uint32(slopeControl(*properties.SlopeControl)) << 10) } if properties.RealWorld != nil { var textureIDs = uint16(entry.Textures) if properties.RealWorld.FloorTexture != nil && (*properties.RealWorld.FloorTexture < 0x20) { textureIDs = (textureIDs & 0x07FF) | (uint16(*properties.RealWorld.FloorTexture) << 11) } if properties.RealWorld.FloorTextureRotations != nil { entry.Floor = (entry.Floor & 0x9F) | ((byte(*properties.RealWorld.FloorTextureRotations) & 0x3) << 5) } if properties.RealWorld.CeilingTexture != nil && (*properties.RealWorld.CeilingTexture < 0x20) { textureIDs = (textureIDs & 0xF83F) | (uint16(*properties.RealWorld.CeilingTexture) << 6) } if properties.RealWorld.CeilingTextureRotations != nil { entry.Ceiling = (entry.Ceiling & 0x9F) | ((byte(*properties.RealWorld.CeilingTextureRotations) & 0x3) << 5) } if properties.RealWorld.WallTexture != nil && (*properties.RealWorld.WallTexture < 0x40) { textureIDs = (textureIDs & 0xFFC0) | uint16(*properties.RealWorld.WallTexture) } if properties.RealWorld.UseAdjacentWallTexture != nil { flags = flags & ^uint32(0x00000100) if *properties.RealWorld.UseAdjacentWallTexture { flags |= 0x00000100 } } if properties.RealWorld.WallTextureOffset != nil && *properties.RealWorld.WallTextureOffset < 0x20 { flags = (flags & ^uint32(0x0000001F)) | uint32(*properties.RealWorld.WallTextureOffset) } entry.Textures = data.TileTextureInfo(textureIDs) } entry.Flags = data.TileFlag(flags) level.onTileDataChanged() }
// TileProperties returns the properties of a specific tile. func (level *Level) TileProperties(x, y int) (result model.TileProperties) { level.mutex.Lock() defer level.mutex.Unlock() entry := level.tileMap.Entry(logic.AtTile(uint16(x), uint16(y))) result.Type = new(model.TileType) *result.Type = tileTypes[entry.Type] result.SlopeHeight = new(model.HeightUnit) *result.SlopeHeight = model.HeightUnit(entry.SlopeHeight) result.FloorHeight = new(model.HeightUnit) *result.FloorHeight = model.HeightUnit(entry.Floor & 0x1F) result.CeilingHeight = new(model.HeightUnit) *result.CeilingHeight = model.HeightUnit(entry.Ceiling & 0x1F) result.SlopeControl = new(model.SlopeControl) *result.SlopeControl = slopeControls[data.SlopeControl((entry.Flags>>10)&0x3)] { result.CalculatedWallHeights = new(model.CalculatedWallHeights) result.CalculatedWallHeights.North = level.calculateWallHeight(entry, DirNorth, x, y+1, DirSouth) result.CalculatedWallHeights.East = level.calculateWallHeight(entry, DirEast, x+1, y, DirWest) result.CalculatedWallHeights.South = level.calculateWallHeight(entry, DirSouth, x, y-1, DirNorth) result.CalculatedWallHeights.West = level.calculateWallHeight(entry, DirWest, x-1, y, DirEast) } { var properties model.RealWorldTileProperties var textureIDs = uint16(entry.Textures) properties.WallTexture = new(int) *properties.WallTexture = int(textureIDs & 0x3F) properties.CeilingTexture = new(int) *properties.CeilingTexture = int((textureIDs >> 6) & 0x1F) properties.CeilingTextureRotations = new(int) *properties.CeilingTextureRotations = int((entry.Ceiling >> 5) & 0x03) properties.FloorTexture = new(int) *properties.FloorTexture = int((textureIDs >> 11) & 0x1F) properties.FloorTextureRotations = new(int) *properties.FloorTextureRotations = int((entry.Floor >> 5) & 0x03) properties.UseAdjacentWallTexture = new(bool) *properties.UseAdjacentWallTexture = (entry.Flags & 0x00000100) != 0 properties.WallTextureOffset = new(model.HeightUnit) *properties.WallTextureOffset = model.HeightUnit(entry.Flags & 0x0000001F) result.RealWorld = &properties } return }
func (level *Level) calculateWallHeight(thisTile *data.TileMapEntry, thisDir Direction, otherX, otherY int, otherDir Direction) float32 { calculatedHeight := float32(0.0) if (solidDirections[thisTile.Type] & thisDir) == 0 { otherType := level.getTileType(otherX, otherY) if (solidDirections[otherType] & otherDir) == 0 { otherTile := level.tileMap.Entry(logic.AtTile(uint16(otherX), uint16(otherY))) thisCeilingHeight := level.calculatedCeilingHeight(thisTile, thisDir) otherCeilingHeight := level.calculatedCeilingHeight(otherTile, otherDir) thisFloorHeight := level.calculatedFloorHeight(thisTile, thisDir) otherFloorHeight := level.calculatedFloorHeight(otherTile, otherDir) if (thisCeilingHeight < otherCeilingHeight) || ((thisCeilingHeight == otherCeilingHeight) && thisFloorHeight < otherFloorHeight) { if (thisFloorHeight >= otherCeilingHeight) || (otherFloorHeight >= thisCeilingHeight) { calculatedHeight = 1.0 } else { minFloorHeight := thisFloorHeight maxFloorHeight := otherFloorHeight minCeilingHeight := thisCeilingHeight if minFloorHeight > otherFloorHeight { minFloorHeight = otherFloorHeight maxFloorHeight = thisFloorHeight } if minCeilingHeight > otherCeilingHeight { minCeilingHeight = otherCeilingHeight } calculatedHeight = (float32(maxFloorHeight) - float32(minFloorHeight)) / (float32(minCeilingHeight) - float32(minFloorHeight)) } } } else { calculatedHeight = 1.0 } } return calculatedHeight }
// 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 }