Add win screen
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 633 B After Width: | Height: | Size: 633 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 255 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,17 @@
|
||||
//go:build !js || !wasm
|
||||
// +build !js !wasm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
)
|
||||
|
||||
func parseFlags(g *game) {
|
||||
flag.BoolVar(&g.godMode, "god", false, "Enable God mode")
|
||||
flag.BoolVar(&g.noclipMode, "noclip", false, "Enable noclip mode")
|
||||
flag.BoolVar(&g.fullBrightMode, "fullbright", false, "Enable fullbright mode")
|
||||
flag.BoolVar(&g.debugMode, "debug", false, "Enable debug mode")
|
||||
flag.BoolVar(&g.muteAudio, "mute", false, "Mute audio")
|
||||
flag.Parse()
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package main
|
||||
|
||||
func parseFlags(g *game) {
|
||||
// Do nothing
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
_ "image/png"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
var ojasDungeonSS *OjasDungeonSpriteSheet
|
||||
|
||||
// OjasDungeonSpriteSheet represents a collection of sprite images.
|
||||
type OjasDungeonSpriteSheet struct {
|
||||
Grass11 *ebiten.Image
|
||||
Grass12 *ebiten.Image
|
||||
Grass13 *ebiten.Image
|
||||
Grass14 *ebiten.Image
|
||||
Grass15 *ebiten.Image
|
||||
Grass16 *ebiten.Image
|
||||
Grass21 *ebiten.Image
|
||||
Grass31 *ebiten.Image
|
||||
Grass41 *ebiten.Image
|
||||
Grass42 *ebiten.Image
|
||||
Grass51 *ebiten.Image
|
||||
Grass61 *ebiten.Image
|
||||
Grass71 *ebiten.Image
|
||||
Grass81 *ebiten.Image
|
||||
Grass82 *ebiten.Image
|
||||
Grass91 *ebiten.Image
|
||||
Wall1 *ebiten.Image
|
||||
Vent1 *ebiten.Image
|
||||
Door11 *ebiten.Image
|
||||
Door12 *ebiten.Image
|
||||
}
|
||||
|
||||
// LoadOjasDungeonSpriteSheet loads the embedded PlayerSpriteSheet.
|
||||
func LoadOjasDungeonSpriteSheet() (*OjasDungeonSpriteSheet, error) {
|
||||
tileSize := 32
|
||||
|
||||
f, err := assetsFS.Open("assets/ojas-dungeon/dungeon-tileset-1.png")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sheet := ebiten.NewImageFromImage(img)
|
||||
|
||||
// spriteAt returns a sprite at the provided coordinates.
|
||||
spriteAt := func(x, y int) *ebiten.Image {
|
||||
return sheet.SubImage(image.Rect(x*tileSize, (y+1)*tileSize, (x+1)*tileSize, y*tileSize)).(*ebiten.Image)
|
||||
}
|
||||
|
||||
// Populate spritesheet.
|
||||
s := &OjasDungeonSpriteSheet{}
|
||||
s.Grass11 = spriteAt(7, 7)
|
||||
s.Grass12 = spriteAt(8, 7)
|
||||
s.Grass13 = spriteAt(9, 7)
|
||||
s.Grass14 = spriteAt(10, 7)
|
||||
s.Grass15 = spriteAt(11, 7)
|
||||
s.Grass16 = spriteAt(12, 7)
|
||||
s.Grass21 = spriteAt(10, 8)
|
||||
s.Grass31 = spriteAt(10, 9)
|
||||
s.Grass41 = spriteAt(15, 9)
|
||||
s.Grass42 = spriteAt(10, 10)
|
||||
s.Grass51 = spriteAt(10, 11)
|
||||
s.Grass61 = spriteAt(10, 12)
|
||||
s.Grass71 = spriteAt(10, 13)
|
||||
s.Grass81 = spriteAt(14, 11)
|
||||
s.Grass82 = spriteAt(10, 14)
|
||||
s.Grass91 = spriteAt(10, 15)
|
||||
s.Wall1 = spriteAt(7, 5)
|
||||
s.Vent1 = spriteAt(9, 13)
|
||||
s.Door11 = spriteAt(3, 6)
|
||||
s.Door12 = spriteAt(3, 7)
|
||||
|
||||
return s, nil
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
func newWinLevel(p *gamePlayer) *Level {
|
||||
l := &Level{
|
||||
w: 256,
|
||||
h: 256,
|
||||
tileSize: 32,
|
||||
player: p,
|
||||
}
|
||||
|
||||
startX, startY := 108, 108
|
||||
|
||||
grid := make([][][]*ebiten.Image, l.w)
|
||||
for x := 0; x < l.w; x++ {
|
||||
grid[x] = make([][]*ebiten.Image, l.h)
|
||||
}
|
||||
|
||||
// Add ground.
|
||||
var lastBones int
|
||||
bonesDistance := 7
|
||||
for x := 0; x < l.w; x++ {
|
||||
excludeBones := x-lastBones < bonesDistance
|
||||
|
||||
r := rand.Intn(33)
|
||||
switch r {
|
||||
case 0:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass11,
|
||||
}
|
||||
case 1:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass12,
|
||||
}
|
||||
case 2:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass13,
|
||||
}
|
||||
case 3:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass14,
|
||||
}
|
||||
case 4:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass15,
|
||||
}
|
||||
case 5:
|
||||
grid[x][startY] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass16,
|
||||
}
|
||||
}
|
||||
grid[x][startY+1] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass21,
|
||||
}
|
||||
grid[x][startY+2] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass31,
|
||||
}
|
||||
if rand.Intn(33) != 0 || excludeBones {
|
||||
grid[x][startY+3] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass41,
|
||||
}
|
||||
} else {
|
||||
grid[x][startY+3] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass42,
|
||||
}
|
||||
}
|
||||
grid[x][startY+4] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass51,
|
||||
}
|
||||
grid[x][startY+5] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass61,
|
||||
}
|
||||
grid[x][startY+6] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass71,
|
||||
}
|
||||
if rand.Intn(33) != 0 || excludeBones {
|
||||
grid[x][startY+7] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass81,
|
||||
}
|
||||
} else {
|
||||
grid[x][startY+7] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass82,
|
||||
}
|
||||
}
|
||||
grid[x][startY+8] = []*ebiten.Image{
|
||||
ojasDungeonSS.Grass91,
|
||||
}
|
||||
}
|
||||
|
||||
// Add dungeon.
|
||||
for x := 0; x < 64; x++ {
|
||||
for y := 0; y < 64; y++ {
|
||||
grid[startX-x-1][startY-y] = []*ebiten.Image{
|
||||
ojasDungeonSS.Wall1,
|
||||
}
|
||||
|
||||
if y == 0 && x%8 == 0 {
|
||||
grid[startX-x-1][startY-y] = append(grid[startX-x-1][startY-y], ojasDungeonSS.Vent1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid[startX-1][startY-1] = append(grid[startX-1][startY-1], ojasDungeonSS.Door11)
|
||||
grid[startX-1][startY] = append(grid[startX-1][startY], ojasDungeonSS.Door12)
|
||||
|
||||
// Add sprites to tiles.
|
||||
l.tiles = make([][]*Tile, l.h)
|
||||
for y := 0; y < l.h; y++ {
|
||||
l.tiles[y] = make([]*Tile, l.w)
|
||||
for x := 0; x < l.w; x++ {
|
||||
t := &Tile{}
|
||||
for _, sprite := range grid[x][y] {
|
||||
t.AddSprite(sprite)
|
||||
}
|
||||
l.tiles[y][x] = t
|
||||
}
|
||||
}
|
||||
|
||||
l.bakeLightmap()
|
||||
|
||||
p.angle = 0
|
||||
p.x, p.y = float64(startX), float64(startY)
|
||||
|
||||
go func() {
|
||||
// Walk away.
|
||||
for i := 0; i < 144; i++ {
|
||||
p.x += 0.05 * (float64(144-i) / 144)
|
||||
time.Sleep(time.Second / 144)
|
||||
}
|
||||
time.Sleep(time.Second / 2)
|
||||
|
||||
// Turn around.
|
||||
p.angle = math.Pi
|
||||
time.Sleep(time.Second / 2)
|
||||
|
||||
throwEnd := float64(startX) - 0.4
|
||||
|
||||
// Throw torch.
|
||||
torchSprite := newCreep(TypeTorch, l, p)
|
||||
torchSprite.x, torchSprite.y = p.x, p.y
|
||||
torchSprite.frames = 1
|
||||
torchSprite.frame = 0
|
||||
torchSprite.sprites = []*ebiten.Image{
|
||||
sandstoneSS.TorchMulti,
|
||||
}
|
||||
|
||||
p.hasTorch = false
|
||||
l.creeps = append(l.creeps, torchSprite)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 144*3; i++ {
|
||||
if torchSprite.x < throwEnd {
|
||||
for i, c := range l.creeps {
|
||||
if c == torchSprite {
|
||||
l.creeps = append(l.creeps[:i], l.creeps[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
torchSprite.x -= 0.05
|
||||
torchSprite.angle -= .1
|
||||
time.Sleep(time.Second / 144)
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second / 2)
|
||||
|
||||
// Throw weapon.
|
||||
weaponSprite := newCreep(TypeTorch, l, p)
|
||||
weaponSprite.x, weaponSprite.y = p.x, p.y
|
||||
weaponSprite.frames = 1
|
||||
weaponSprite.frame = 0
|
||||
weaponSprite.sprites = []*ebiten.Image{
|
||||
imageAtlas[ImageUzi],
|
||||
}
|
||||
|
||||
p.weapon = nil
|
||||
l.creeps = append(l.creeps, weaponSprite)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 144*3; i++ {
|
||||
if weaponSprite.x < throwEnd {
|
||||
for i, c := range l.creeps {
|
||||
if c == weaponSprite {
|
||||
l.creeps = append(l.creeps[:i], l.creeps[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
weaponSprite.x -= 0.05
|
||||
weaponSprite.angle -= .1
|
||||
time.Sleep(time.Second / 144)
|
||||
}
|
||||
}()
|
||||
|
||||
// Walk away.
|
||||
time.Sleep(time.Second / 2)
|
||||
|
||||
p.angle = 0
|
||||
time.Sleep(time.Second / 2)
|
||||
for i := 0; i < 144; i++ {
|
||||
p.x += 0.05 * (float64(i) / 144)
|
||||
time.Sleep(time.Second / 144)
|
||||
}
|
||||
for i := 0; i < 144*12; i++ {
|
||||
if p.health > 0 {
|
||||
// Game has restarted.
|
||||
return
|
||||
}
|
||||
p.x += 0.05
|
||||
time.Sleep(time.Second / 144)
|
||||
}
|
||||
|
||||
return
|
||||
t := time.NewTicker(time.Second / 144)
|
||||
for range t.C {
|
||||
p.x += 0.05
|
||||
p.angle += 0.1
|
||||
}
|
||||
}()
|
||||
|
||||
return l
|
||||
}
|