mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 10:34:06 +09:00
A commit to save my soul as I'm going to fuck up things a bit...
This commit is contained in:
132
ABOUT.md
132
ABOUT.md
@@ -1,132 +0,0 @@
|
|||||||
## About gamemaking ##
|
|
||||||
|
|
||||||
### CHALLENGING, NOT PUNISHING ###
|
|
||||||
https://www.youtube.com/watch?v=ea6UuRTjkKs
|
|
||||||
|
|
||||||
1. CONSISTENT RULES
|
|
||||||
- No arbitrary unstoppable death
|
|
||||||
|
|
||||||
2. Player's skill involved
|
|
||||||
- Can play around, not restart
|
|
||||||
|
|
||||||
3. Usability of in-game tools
|
|
||||||
- Players should be able to 'regret' their strategy and adjust.
|
|
||||||
|
|
||||||
4. Comfortable control
|
|
||||||
|
|
||||||
5. Make players overcome the challenge, not defeating them
|
|
||||||
|
|
||||||
6. Let players have "aha" moment when they failed.
|
|
||||||
- Make them hungry to retry with new strategies.
|
|
||||||
- Some small things they've could done differently
|
|
||||||
- e.g. "One-big-hit didn't worked, may I should've picked up high DPS one"
|
|
||||||
|
|
||||||
|
|
||||||
### MORE DEPTH, LESS COMPLEXITY ###
|
|
||||||
https://www.youtube.com/watch?v=jVL4st0blGU
|
|
||||||
|
|
||||||
1. Memorise less!
|
|
||||||
- Less burden to, even starting the game
|
|
||||||
- Start with gentle learning curve, getting slowly steep
|
|
||||||
- Intuitive UX (UI, control, ...)
|
|
||||||
- Good tutorial = lessens complexity
|
|
||||||
|
|
||||||
2. Intuitive!
|
|
||||||
|
|
||||||
3. Calculations per second
|
|
||||||
- reduce!
|
|
||||||
|
|
||||||
4. Players have to know everything to even begin the play ### FAIL (irreducible complexity)
|
|
||||||
- Make them get familiar with rules of the game
|
|
||||||
- Dwarf Fortress failed this!
|
|
||||||
|
|
||||||
|
|
||||||
### Lots of things players can play with (aka don't make them bored) ###
|
|
||||||
|
|
||||||
- Combat, battle, building, mechanics, adventure, dungeon explore, spelunking
|
|
||||||
- Not scaled; easy combat, tough combat, tedious combat, etc.
|
|
||||||
|
|
||||||
|
|
||||||
### Achieving perfect imbalance ###
|
|
||||||
https://www.youtube.com/watch?v=e31OSVZF77w
|
|
||||||
|
|
||||||
- Make sure no matter how you skilled, your playable character cannot be good at everything
|
|
||||||
- Give players __wide pool of options__ to solve problem
|
|
||||||
(kill the boss, defend their adobe, fast transportation, etc.)
|
|
||||||
|
|
||||||
|
|
||||||
**_What feeling do you want to convey?_**
|
|
||||||
|
|
||||||
|
|
||||||
### Always think WHY you want to add _something_ on the game ###
|
|
||||||
|
|
||||||
- e.g. Why are you adding RPG leveling system? What it would do to the players? How would they play with?
|
|
||||||
|
|
||||||
|
|
||||||
See also: *HEARTS, CLUBS, DIAMONDS, SPADES: PLAYERS WHO SUIT MUDS*
|
|
||||||
|
|
||||||
|
|
||||||
## About this very game ##
|
|
||||||
|
|
||||||
### Friendlier version of Dwarf Fortress Adventure mode ###
|
|
||||||
|
|
||||||
- Yet _lots of fun_
|
|
||||||
- Add Fortress mode features by 'make your own settling'
|
|
||||||
- Hard to actually die, but once you die, you're done.
|
|
||||||
+ Config: imtooyoungtodie for easy mode
|
|
||||||
|
|
||||||
- Genre: Adventure, Open world (towns in RPG, building, town managing (conquer existing one or
|
|
||||||
you build one and persuade existing people to move in) -> See Dwarf Fortress and Animal Crossing)
|
|
||||||
|
|
||||||
* Adventure: adventure this vast—5,5 km wide—world, discover new (and good/horrible) things
|
|
||||||
|
|
||||||
* Open world:
|
|
||||||
- Building: building your own houses, structures, etc.
|
|
||||||
- Town managing:
|
|
||||||
1. Build your own little hamlet and manage it
|
|
||||||
or-
|
|
||||||
2. Conquer existing one and become a ruler
|
|
||||||
The town is a special hamlet that can be tailored for your taste
|
|
||||||
- Survival:
|
|
||||||
mobs will trying to attack your assets (yourself, your hamlet, your people)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Side view ###
|
|
||||||
|
|
||||||
### Interact menu w/ mouse right ###
|
|
||||||
|
|
||||||
### Pixelated sprites ###
|
|
||||||
- Use 2x sprites if rotating does not work well
|
|
||||||
|
|
||||||
|
|
||||||
### User experience ###
|
|
||||||
|
|
||||||
* Indicative mouse cursor
|
|
||||||
|
|
||||||
|
|
||||||
### Game mechanics ###
|
|
||||||
|
|
||||||
* 24 pixels == 1 metre
|
|
||||||
|
|
||||||
|
|
||||||
### Purpose of the game ###
|
|
||||||
|
|
||||||
* Boss
|
|
||||||
- Will be mentioned/shown as absolute _evil_.
|
|
||||||
- But actually is not.
|
|
||||||
|
|
||||||
* Theme
|
|
||||||
- Is an evil really really is what we think?
|
|
||||||
- Is there a thing as 'absolute evil'?
|
|
||||||
|
|
||||||
* Boss character
|
|
||||||
- From debugger character
|
|
||||||
- Name key: "Sigriðr hinn Dróttningin" (can be changed)
|
|
||||||
* Little setting
|
|
||||||
- A ruler, hated by people
|
|
||||||
|
|
||||||
* Mechanics
|
|
||||||
- Beating boss does not ends the game, but grants an ability to
|
|
||||||
create new character as it.
|
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ class TestPick extends GameItem {
|
|||||||
boolean stackable = true
|
boolean stackable = true
|
||||||
int maxDurability = 147
|
int maxDurability = 147
|
||||||
float durability = maxDurability
|
float durability = maxDurability
|
||||||
int equipPosition = EquipPosition.HAND_GRIP
|
int equipPosition = 9 //EquipPosition.HAND_GRIP
|
||||||
String inventoryCategory = Category.TOOL
|
String inventoryCategory = "tool" //Category.TOOL
|
||||||
|
|
||||||
// !! TEST MATERIAL !!
|
// !! TEST MATERIAL !!
|
||||||
Material material = new Material(0,0,0,0,0,0,0,0,1,0.0)
|
Material material = new Material(0,0,0,0,0,0,0,0,1,0.0)
|
||||||
|
|||||||
211
assets/modules/dwarventech/virtualcomputer/arstars.kts
Normal file
211
assets/modules/dwarventech/virtualcomputer/arstars.kts
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just to make things slow down
|
||||||
|
*
|
||||||
|
* This version of Brainfuck fills memory with sanitised input program, and initialises
|
||||||
|
* memory pointer to be just right after your input program. This brings three major improvements:
|
||||||
|
*
|
||||||
|
* 1. Possibility of Self-modifying code
|
||||||
|
* 2. Fucks your brain even more
|
||||||
|
* 3. Forces you to enhance your calm
|
||||||
|
*
|
||||||
|
* Also note that program counter and memory pointer will wrap around when commands are executed,
|
||||||
|
* but not when program is being loaded (will throw OutOfMemoryException).
|
||||||
|
*
|
||||||
|
* If memory at Program Counter is equal to 0xFF, it is interpreted as termination. (0xFF is NOT a
|
||||||
|
* valid opcode for input program, however)
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 17-04-29.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BFVM(
|
||||||
|
val memSize: Int = 65536,
|
||||||
|
val stdout: OutputStream = System.out,
|
||||||
|
val stdin: InputStream = System.`in`
|
||||||
|
) {
|
||||||
|
private val ZERO = 0.toByte()
|
||||||
|
|
||||||
|
private val INP = '>'.toByte()
|
||||||
|
private val DEP = '<'.toByte()
|
||||||
|
private val INC = '+'.toByte()
|
||||||
|
private val DEC = '-'.toByte()
|
||||||
|
private val PRN = '.'.toByte()
|
||||||
|
private val RDI = ','.toByte()
|
||||||
|
private val JPZ = '['.toByte()
|
||||||
|
private val JPN = ']'.toByte()
|
||||||
|
private val CYA = 0xFF.toByte()
|
||||||
|
|
||||||
|
private val bfOpcodes = hashSetOf<Byte>(43,44,45,46,60,62,91,93)
|
||||||
|
|
||||||
|
private val instSet = hashMapOf<Byte, () -> Unit>(
|
||||||
|
Pair(INP, { INP() }),
|
||||||
|
Pair(DEP, { DEP() }),
|
||||||
|
Pair(INC, { INC() }),
|
||||||
|
Pair(DEC, { DEC() }),
|
||||||
|
Pair(PRN, { PRN() }),
|
||||||
|
Pair(RDI, { RDI() }),
|
||||||
|
Pair(JPZ, { JPZ() }),
|
||||||
|
Pair(JPN, { JPN() })
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
private var r1: Byte = ZERO // Register One (Data register)
|
||||||
|
private var r2 = 0 // Register Two (Scratchpad); theoretically I can use R1 but it limits bracket depth to 254
|
||||||
|
private var mp = 0 // Memory Pointer
|
||||||
|
private var pc = 0 // Program Counter
|
||||||
|
private var ir = 0 // Instruction Register; does lookahead ahd lookbehind
|
||||||
|
|
||||||
|
private val mem = ByteArray(memSize)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input program is loaded into the memory from index zero.
|
||||||
|
|
||||||
|
Interrupts are hard-coded, 'cause why not?
|
||||||
|
|
||||||
|
Code Mnemo. Desc.
|
||||||
|
----|------|-----
|
||||||
|
INP > Increment pointer
|
||||||
|
DEP < Decrement pointer
|
||||||
|
INC + Increment memory
|
||||||
|
DEC - Decrement memory
|
||||||
|
PRN . Print as text
|
||||||
|
RDI , Read from input
|
||||||
|
JPZ [ Jump past to matching ] when mem is zero
|
||||||
|
JPN ] Jump back to matching [ when mem is non-zero
|
||||||
|
|
||||||
|
[ Internal operations ]
|
||||||
|
CYA 0xFF Marks end of the input program
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NOTE: INC_PC is implied
|
||||||
|
private fun INP() {
|
||||||
|
INC_MP()
|
||||||
|
}
|
||||||
|
private fun DEP() {
|
||||||
|
DEC_MP()
|
||||||
|
}
|
||||||
|
private fun INC() {
|
||||||
|
r1 = mem[mp]
|
||||||
|
r1++
|
||||||
|
mem[mp] = r1
|
||||||
|
}
|
||||||
|
private fun DEC() {
|
||||||
|
r1 = mem[mp]
|
||||||
|
r1--
|
||||||
|
mem[mp] = r1
|
||||||
|
}
|
||||||
|
private fun PRN() {
|
||||||
|
stdout.write(mem[mp].toInt())
|
||||||
|
}
|
||||||
|
private fun RDI() {
|
||||||
|
r1 = stdin.read().toByte()
|
||||||
|
mem[mp] = r1
|
||||||
|
}
|
||||||
|
private fun JPZ() {
|
||||||
|
if (mem[mp] == ZERO) {
|
||||||
|
// lookahead
|
||||||
|
ir = pc
|
||||||
|
r2 = 0
|
||||||
|
|
||||||
|
while (r2 != -1) {
|
||||||
|
INC_IR()
|
||||||
|
if (JPZ == mem[ir]) {
|
||||||
|
r2++
|
||||||
|
}
|
||||||
|
else if (JPN == mem[ir]) {
|
||||||
|
r2--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pc = ir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun JPN() {
|
||||||
|
if (mem[mp] != ZERO) {
|
||||||
|
// lookbehind
|
||||||
|
ir = pc
|
||||||
|
r2 = 0
|
||||||
|
|
||||||
|
while (r2 != -1) {
|
||||||
|
DEC_IR()
|
||||||
|
if (JPN == mem[ir]) {
|
||||||
|
r2++
|
||||||
|
}
|
||||||
|
else if (JPZ == mem[ir]) {
|
||||||
|
r2--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pc = ir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// END OF NOTE (INC_PC is implied)
|
||||||
|
|
||||||
|
|
||||||
|
fun execute() {
|
||||||
|
while (mem[pc] != CYA) {
|
||||||
|
//println("pc = $pc, mp = $mp, inst = ${mem[pc].toChar()}, mem = ${mem[mp]}")
|
||||||
|
instSet[mem[pc]]?.invoke() // fetch-decode-execute in one line
|
||||||
|
INC_PC()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadProgram(program: String) {
|
||||||
|
val program = program.toByteArray(charset = Charsets.US_ASCII)
|
||||||
|
|
||||||
|
pc = 0 // FOR NOW it's PC for input program
|
||||||
|
mp = 0 // where to dump input bytes
|
||||||
|
|
||||||
|
while (pc < program.size) {
|
||||||
|
if (pc >= memSize - 1) {
|
||||||
|
throw OutOfMemoryError("Virtual Machine Out of Memory")
|
||||||
|
}
|
||||||
|
|
||||||
|
r1 = program[pc]
|
||||||
|
|
||||||
|
if (r1 in bfOpcodes) {
|
||||||
|
mem[mp] = r1
|
||||||
|
INC_MP()
|
||||||
|
}
|
||||||
|
|
||||||
|
INC_PC()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mem[program.size] = CYA
|
||||||
|
mp = (program.size + 1) mod memSize
|
||||||
|
pc = 0
|
||||||
|
ir = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun INC_PC() { pc = (pc + 1) mod memSize }
|
||||||
|
private fun INC_IR() { ir = (ir + 1) mod memSize }
|
||||||
|
private fun DEC_IR() { ir = (ir - 1) mod memSize }
|
||||||
|
private fun INC_MP() { mp = (mp + 1) mod memSize }
|
||||||
|
private fun DEC_MP() { mp = (mp - 1) mod memSize }
|
||||||
|
private infix fun Int.mod(other: Int) = Math.floorMod(this, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val vm = BFVM()
|
||||||
|
|
||||||
|
val factorials = """
|
||||||
|
+++++++++++
|
||||||
|
>+>>>>++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>
|
||||||
|
+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-
|
||||||
|
<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<
|
||||||
|
-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]
|
||||||
|
>[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++
|
||||||
|
+++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++
|
||||||
|
++++++++++++++++++++++++++++++++++++++++++++.[-]<<
|
||||||
|
<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<
|
||||||
|
[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]
|
||||||
|
"""
|
||||||
|
|
||||||
|
vm.loadProgram(factorials)
|
||||||
|
vm.execute()
|
||||||
@@ -25,6 +25,11 @@ class BFVM(
|
|||||||
val stdout: OutputStream = System.out,
|
val stdout: OutputStream = System.out,
|
||||||
val stdin: InputStream = System.`in`
|
val stdin: InputStream = System.`in`
|
||||||
) {
|
) {
|
||||||
|
annotation class Unsigned
|
||||||
|
|
||||||
|
private val DEBUG = true
|
||||||
|
|
||||||
|
|
||||||
private val ZERO = 0.toByte()
|
private val ZERO = 0.toByte()
|
||||||
|
|
||||||
private val INP = '>'.toByte()
|
private val INP = '>'.toByte()
|
||||||
@@ -35,8 +40,16 @@ class BFVM(
|
|||||||
private val RDI = ','.toByte()
|
private val RDI = ','.toByte()
|
||||||
private val JPZ = '['.toByte()
|
private val JPZ = '['.toByte()
|
||||||
private val JPN = ']'.toByte()
|
private val JPN = ']'.toByte()
|
||||||
|
|
||||||
private val CYA = 0xFF.toByte()
|
private val CYA = 0xFF.toByte()
|
||||||
|
|
||||||
|
private val LDZ = '0'.toByte()
|
||||||
|
private val ADM = 'M'.toByte()
|
||||||
|
private val ADP = 'P'.toByte()
|
||||||
|
private val SBM = 'm'.toByte()
|
||||||
|
private val SBP = 'p'.toByte()
|
||||||
|
|
||||||
|
|
||||||
private val bfOpcodes = hashSetOf<Byte>(43,44,45,46,60,62,91,93)
|
private val bfOpcodes = hashSetOf<Byte>(43,44,45,46,60,62,91,93)
|
||||||
|
|
||||||
private val instSet = hashMapOf<Byte, () -> Unit>(
|
private val instSet = hashMapOf<Byte, () -> Unit>(
|
||||||
@@ -47,9 +60,16 @@ class BFVM(
|
|||||||
Pair(PRN, { PRN() }),
|
Pair(PRN, { PRN() }),
|
||||||
Pair(RDI, { RDI() }),
|
Pair(RDI, { RDI() }),
|
||||||
Pair(JPZ, { JPZ() }),
|
Pair(JPZ, { JPZ() }),
|
||||||
Pair(JPN, { JPN() })
|
Pair(JPN, { JPN() }),
|
||||||
|
Pair(LDZ, { LDZ() })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val instOneArg = hashMapOf<@Unsigned Byte, (Int) -> Unit>(
|
||||||
|
Pair(ADM, { i -> ADM(i) }),
|
||||||
|
Pair(ADP, { i -> ADP(i) }),
|
||||||
|
Pair(SBM, { i -> SBM(i) }),
|
||||||
|
Pair(SBP, { i -> SBP(i) })
|
||||||
|
)
|
||||||
|
|
||||||
private var r1: Byte = ZERO // Register One (Data register)
|
private var r1: Byte = ZERO // Register One (Data register)
|
||||||
private var r2 = 0 // Register Two (Scratchpad); theoretically I can use R1 but it limits bracket depth to 254
|
private var r2 = 0 // Register Two (Scratchpad); theoretically I can use R1 but it limits bracket depth to 254
|
||||||
@@ -78,6 +98,14 @@ class BFVM(
|
|||||||
|
|
||||||
[ Internal operations ]
|
[ Internal operations ]
|
||||||
CYA 0xFF Marks end of the input program
|
CYA 0xFF Marks end of the input program
|
||||||
|
|
||||||
|
[ Optimise operations ]
|
||||||
|
LDZ 0 Set memory to zero
|
||||||
|
ADM M Add immediate to memory (RLEing +)
|
||||||
|
ADP P Add immediate to memory pointer (RLEing >)
|
||||||
|
SBM m Subtract immediate to memory (RLEing -)
|
||||||
|
SBP p Subtract immediate to memory pointer (RLEing <)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: INC_PC is implied
|
// NOTE: INC_PC is implied
|
||||||
@@ -98,7 +126,7 @@ class BFVM(
|
|||||||
mem[mp] = r1
|
mem[mp] = r1
|
||||||
}
|
}
|
||||||
private fun PRN() {
|
private fun PRN() {
|
||||||
stdout.write(mem[mp].toInt())
|
stdout.write(mem[mp].toUint())
|
||||||
}
|
}
|
||||||
private fun RDI() {
|
private fun RDI() {
|
||||||
r1 = stdin.read().toByte()
|
r1 = stdin.read().toByte()
|
||||||
@@ -111,7 +139,7 @@ class BFVM(
|
|||||||
r2 = 0
|
r2 = 0
|
||||||
|
|
||||||
while (r2 != -1) {
|
while (r2 != -1) {
|
||||||
INC_IR()
|
ir++
|
||||||
if (JPZ == mem[ir]) {
|
if (JPZ == mem[ir]) {
|
||||||
r2++
|
r2++
|
||||||
}
|
}
|
||||||
@@ -130,7 +158,7 @@ class BFVM(
|
|||||||
r2 = 0
|
r2 = 0
|
||||||
|
|
||||||
while (r2 != -1) {
|
while (r2 != -1) {
|
||||||
DEC_IR()
|
ir--
|
||||||
if (JPN == mem[ir]) {
|
if (JPN == mem[ir]) {
|
||||||
r2++
|
r2++
|
||||||
}
|
}
|
||||||
@@ -142,22 +170,67 @@ class BFVM(
|
|||||||
pc = ir
|
pc = ir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// non-standard
|
||||||
|
private fun LDZ() {
|
||||||
|
mem[mp] = 0
|
||||||
|
}
|
||||||
|
private fun ADM(i: Int) {
|
||||||
|
mem[mp] = (mem[mp] + i).toByte()
|
||||||
|
}
|
||||||
|
private fun SBM(i: Int) {
|
||||||
|
mem[mp] = (mem[mp] - i).toByte()
|
||||||
|
}
|
||||||
|
private fun ADP(i: Int) {
|
||||||
|
mp = (mp + i) mod memSize
|
||||||
|
}
|
||||||
|
private fun SBP(i: Int) {
|
||||||
|
mp = (mp - i) mod memSize
|
||||||
|
}
|
||||||
// END OF NOTE (INC_PC is implied)
|
// END OF NOTE (INC_PC is implied)
|
||||||
|
|
||||||
|
|
||||||
fun execute() {
|
fun execute() {
|
||||||
|
dbgp("Now run...")
|
||||||
while (mem[pc] != CYA) {
|
while (mem[pc] != CYA) {
|
||||||
//println("pc = $pc, mp = $mp, inst = ${mem[pc].toChar()}, mem = ${mem[mp]}")
|
//dbgp("pc = $pc, mp = $mp, inst = ${mem[pc].toChar()} ${mem[pc+1]}, mem = ${mem[mp]}")
|
||||||
instSet[mem[pc]]?.invoke() // fetch-decode-execute in one line
|
|
||||||
|
r1 = mem[pc]
|
||||||
|
|
||||||
|
if (r1 in instSet) {
|
||||||
|
instSet[r1]!!.invoke() // fetch-decode-execute in one line
|
||||||
|
}
|
||||||
|
else if (r1 in instOneArg) {
|
||||||
|
INC_PC()
|
||||||
|
r2 = mem[pc].toUint()
|
||||||
|
|
||||||
|
instOneArg[r1]?.invoke(r2)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dbgp("invalid: $r1")
|
||||||
|
}
|
||||||
|
|
||||||
INC_PC()
|
INC_PC()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadProgram(program: String) {
|
fun loadProgram(program: String, optimizeLevel: Int = NO_OPTIMISE) {
|
||||||
|
dbgp("Now load...")
|
||||||
|
|
||||||
|
fun putOp(op: Byte) {
|
||||||
|
|
||||||
|
//dbgp("${op.toChar()} ${op.toUint()}")
|
||||||
|
|
||||||
|
mem[mp] = op
|
||||||
|
INC_MP()
|
||||||
|
}
|
||||||
|
|
||||||
val program = program.toByteArray(charset = Charsets.US_ASCII)
|
val program = program.toByteArray(charset = Charsets.US_ASCII)
|
||||||
|
|
||||||
|
r1 = 0 // currently reading operation
|
||||||
pc = 0 // FOR NOW it's PC for input program
|
pc = 0 // FOR NOW it's PC for input program
|
||||||
mp = 0 // where to dump input bytes
|
mp = 0 // where to dump input bytes
|
||||||
|
r2 = 0 // scratchpad
|
||||||
|
ir = 0 // lookahead pointer
|
||||||
|
|
||||||
while (pc < program.size) {
|
while (pc < program.size) {
|
||||||
if (pc >= memSize - 1) {
|
if (pc >= memSize - 1) {
|
||||||
@@ -167,62 +240,109 @@ class BFVM(
|
|||||||
r1 = program[pc]
|
r1 = program[pc]
|
||||||
|
|
||||||
if (r1 in bfOpcodes) {
|
if (r1 in bfOpcodes) {
|
||||||
mem[mp] = r1
|
if (optimizeLevel >= 1) {
|
||||||
INC_MP()
|
// [-]
|
||||||
|
if (r1 == JPZ) {
|
||||||
|
if (program[pc + 1] == DEC && program[pc + 2] == JPN) {
|
||||||
|
pc += 3
|
||||||
|
putOp(LDZ)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// RLEing +
|
||||||
|
else if (INC == r1 && program[pc + 1] == r1) {
|
||||||
|
ir = 2
|
||||||
|
while (INC == program[pc + ir] && ir < 255) ir++
|
||||||
|
|
||||||
|
pc += ir
|
||||||
|
putOp(ADM)
|
||||||
|
putOp(ir.toByte())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// RLEing -
|
||||||
|
else if (DEC == r1 && program[pc + 1] == r1) {
|
||||||
|
ir = 2
|
||||||
|
while (DEC == program[pc + ir] && ir < 255) ir++
|
||||||
|
|
||||||
|
pc += ir
|
||||||
|
putOp(SBM)
|
||||||
|
putOp(ir.toByte())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// RLEing >
|
||||||
|
else if (INP == r1 && program[pc + 1] == r1) {
|
||||||
|
ir = 2
|
||||||
|
while (INP == program[pc + ir] && ir < 255) ir++
|
||||||
|
|
||||||
|
pc += ir
|
||||||
|
putOp(ADP)
|
||||||
|
putOp(ir.toByte())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// RLEing <
|
||||||
|
else if (DEP == r1 && program[pc + 1] == r1) {
|
||||||
|
ir = 2
|
||||||
|
while (DEP == program[pc + ir] && ir < 255) ir++
|
||||||
|
|
||||||
|
pc += ir
|
||||||
|
putOp(SBP)
|
||||||
|
putOp(ir.toByte())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putOp(r1)
|
||||||
}
|
}
|
||||||
|
|
||||||
INC_PC()
|
pc += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mem[program.size] = CYA
|
mem[mp] = CYA
|
||||||
mp = (program.size + 1) mod memSize
|
|
||||||
|
dbgp("Prg size: $mp")
|
||||||
|
|
||||||
|
INC_MP()
|
||||||
pc = 0
|
pc = 0
|
||||||
ir = 0
|
ir = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun INC_PC() { pc = (pc + 1) mod memSize }
|
private fun INC_PC() { pc = (pc + 1) mod memSize }
|
||||||
private fun INC_IR() { ir = (ir + 1) mod memSize }
|
|
||||||
private fun DEC_IR() { ir = (ir - 1) mod memSize }
|
|
||||||
private fun INC_MP() { mp = (mp + 1) mod memSize }
|
private fun INC_MP() { mp = (mp + 1) mod memSize }
|
||||||
private fun DEC_MP() { mp = (mp - 1) mod memSize }
|
private fun DEC_MP() { mp = (mp - 1) mod memSize }
|
||||||
private infix fun Int.mod(other: Int) = Math.floorMod(this, other)
|
private infix fun Int.mod(other: Int) = Math.floorMod(this, other)
|
||||||
|
private fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this)
|
||||||
|
|
||||||
|
private fun dbgp(s: Any) {
|
||||||
|
if (DEBUG) println(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
val NO_OPTIMISE = 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optimise level
|
||||||
|
1 RLE, Set cell to zero
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val vm = BFVM()
|
val vm = BFVM()
|
||||||
|
|
||||||
val factorials = """
|
val factorials = """
|
||||||
github (dot) com/saulpw/brainfuck/blob/master/tests/facto (dot) b
|
+++++++++++
|
||||||
|
>+>>>>++++++++++++++++++++++++++++++++++++++++++++
|
||||||
++++++++++>>>+>>>>+>+<[[+++++[>++++
|
>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>
|
||||||
++++<-]>.<++++++[>--------<-]+<<]<<
|
+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-
|
||||||
[<<]<.>>>>+<[->[<+>-[<+>-[<+>-[<+>-
|
<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<
|
||||||
[<+>-[<+>-[<+>-[<+>-[<+>-[<[-]>-+>[
|
-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]
|
||||||
<->-]<[->>>[>>]<<[->[>>+<<-]>+<<<<]
|
>[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++
|
||||||
<]>[-]+>+<<]]]]]]]]]]<[>+<-]+>>]<<[
|
+++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++
|
||||||
<<]>>[->>[>>]>>[-<<[<<]<<[<<]>[>[>>
|
++++++++++++++++++++++++++++++++++++++++++++.[-]<<
|
||||||
]>>[>>]>>[>>]>+>+<<<<[<<]<<[<<]<<[<
|
<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<
|
||||||
<]>-]>[>>]>>[>>]>>[>>]>[<<<[<<]<<[<
|
[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]
|
||||||
<]<<[<<]>+>[>>]>>[>>]>>[>>]>-]<<<[<
|
|
||||||
<]>[>[>>]>+>>+<<<<<[<<]>-]>[>>]>[<<
|
|
||||||
<[<<]>+>[>>]>-]>>[<[<<+>+>-]<[>>>+<
|
|
||||||
<<-]<[>>+<<-]>>>-]<[-]>>+[>[>>>>]>[
|
|
||||||
>>>>]>[-]+>+<[<<<<]>-]>[>>>>]>[>>>>
|
|
||||||
]>->-[<<<+>>+>-]<[>+<-]>[[<<+>+>-]<
|
|
||||||
[<->-[<->-[<->-[<->-[<->-[<->-[<->-
|
|
||||||
[<->-[<->-[<-<---------->>[-]>>>>[-
|
|
||||||
]+>+<<<<<]]]]]]]]]]<[>>+<<-]>>]<+<+
|
|
||||||
<[>>>+<<<-]<<[<<<<]<<<<<[<<]+>>]>>>
|
|
||||||
>>[>>>>]+>[>>>>]<<<<[-<<<<]>>>>>[<<
|
|
||||||
<<]<<<<<[<<]<<[<<]+>>]>>[>>]>>>>>[-
|
|
||||||
>>>>]<<[<<<<]>>>>[>>>>]<<<<<<<<[>>>
|
|
||||||
>[<<+>>->[<<+>>-]>]<<<<[<<]<<]<<<<<
|
|
||||||
[->[-]>>>>>>>>[<<+>>->[<<+>>-]>]<<<
|
|
||||||
<[<<]<<<<<<<]>>>>>>>>>[<<<<<<<+>>>>
|
|
||||||
>>>->[<<<<<<<+>>>>>>>-]>]<<<<<<<<<]
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
vm.loadProgram(factorials)
|
vm.loadProgram(factorials, optimizeLevel = 1)
|
||||||
vm.execute()
|
vm.execute()
|
||||||
|
|
||||||
|
|||||||
@@ -834,9 +834,9 @@ class StateInGame : BasicGameState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ArrayList<out Actor>.binarySearch(actor: Actor) = this.binarySearch(actor.referenceID)
|
private fun ArrayList<*>.binarySearch(actor: Actor) = this.binarySearch(actor.referenceID)
|
||||||
|
|
||||||
private fun ArrayList<out Actor>.binarySearch(ID: Int): Int {
|
private fun ArrayList<*>.binarySearch(ID: Int): Int {
|
||||||
// code from collections/Collections.kt
|
// code from collections/Collections.kt
|
||||||
var low = 0
|
var low = 0
|
||||||
var high = this.size - 1
|
var high = this.size - 1
|
||||||
@@ -844,11 +844,11 @@ class StateInGame : BasicGameState() {
|
|||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
val mid = (low + high).ushr(1) // safe from overflows
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
|
||||||
val midVal = get(mid)
|
val midVal = get(mid)!!
|
||||||
|
|
||||||
if (ID > midVal.referenceID)
|
if (ID > midVal.hashCode())
|
||||||
low = mid + 1
|
low = mid + 1
|
||||||
else if (ID < midVal.referenceID)
|
else if (ID < midVal.hashCode())
|
||||||
high = mid - 1
|
high = mid - 1
|
||||||
else
|
else
|
||||||
return mid // key found
|
return mid // key found
|
||||||
|
|||||||
61
work_files/GameDesign/ABOUT.md
Normal file
61
work_files/GameDesign/ABOUT.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
## Friendlier version of Dwarf Fortress Adventure mode
|
||||||
|
|
||||||
|
- Yet lots of !!fun!! (wat that double exclamation mark!)
|
||||||
|
- You can build your own hamlet (Dwarf "Fortress" reference)
|
||||||
|
- You die, you lose "you"; the world will be there, some of your possession will be on the ground, but you got to start over by making new character from scratch
|
||||||
|
- Unless you have built Resurrection Shrine, which you won't going to easily build it
|
||||||
|
|
||||||
|
- Genre: Adventure, Open world (towns in RPG, building, town managing (conquer existing one or
|
||||||
|
you build one and persuade existing people to move in) -> See Dwarf Fortress and Animal Crossing)
|
||||||
|
|
||||||
|
* Adventure: adventure this vast—5,5 km wide—world, discover new (and good/horrible) things
|
||||||
|
|
||||||
|
* Open world:
|
||||||
|
- Building: building your own houses, structures, etc.
|
||||||
|
- Town managing:
|
||||||
|
1. Build your own little hamlet and manage it
|
||||||
|
or-
|
||||||
|
2. Conquer existing one and become a ruler
|
||||||
|
The town is a special hamlet that can be tailored for your taste
|
||||||
|
- Survival:
|
||||||
|
mobs will trying to attack your assets (yourself, your hamlet, your people)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Side view
|
||||||
|
|
||||||
|
## Interact menu w/ mouse right
|
||||||
|
|
||||||
|
|
||||||
|
## User experience
|
||||||
|
|
||||||
|
* Indicative mouse cursor
|
||||||
|
|
||||||
|
|
||||||
|
## Game mechanics
|
||||||
|
|
||||||
|
* 24 pixels == 1 metre
|
||||||
|
|
||||||
|
|
||||||
|
## Purpose of the game
|
||||||
|
|
||||||
|
* Boss
|
||||||
|
- Will be mentioned/shown as absolute _evil_.
|
||||||
|
- But actually is not.
|
||||||
|
|
||||||
|
* Theme
|
||||||
|
- Is an evil really really is what we think?
|
||||||
|
- Is there a thing as 'absolute evil'?
|
||||||
|
|
||||||
|
* Boss character
|
||||||
|
- From debugger character
|
||||||
|
- Name key: "Sigriðr hinn Dróttningin" (can be changed)
|
||||||
|
* Little setting
|
||||||
|
- A ruler, hated by people
|
||||||
|
|
||||||
|
* Mechanics
|
||||||
|
- Beating boss does not ends the game, but grants an ability to
|
||||||
|
create new character as it.
|
||||||
|
|
||||||
|
...We need to re-think about it. —Torvald, 2017-04-30
|
||||||
66
work_files/GameDesign/GAME_DESIGN_PRINCIPLE.md
Normal file
66
work_files/GameDesign/GAME_DESIGN_PRINCIPLE.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
(Warning — this article refers Extra Credits bit too much...)
|
||||||
|
|
||||||
|
## CHALLENGING, NOT PUNISHING
|
||||||
|
https://www.youtube.com/watch?v=ea6UuRTjkKs
|
||||||
|
|
||||||
|
1. CONSISTENT RULES
|
||||||
|
- No arbitrary unstoppable death
|
||||||
|
|
||||||
|
2. Player's skill involved
|
||||||
|
- Can play around, not restart
|
||||||
|
|
||||||
|
3. Usability of in-game tools
|
||||||
|
- Players should be able to 'regret' their strategy and adjust.
|
||||||
|
|
||||||
|
4. Comfortable control
|
||||||
|
|
||||||
|
5. Make players overcome the challenge, not defeating them
|
||||||
|
|
||||||
|
6. Let players have "aha" moment when they failed.
|
||||||
|
- Make them hungry to retry with new strategies.
|
||||||
|
- Some small things they've could done differently
|
||||||
|
- e.g. "One-big-hit didn't worked, may I should've picked up high DPS one"
|
||||||
|
|
||||||
|
|
||||||
|
## MORE DEPTH, LESS COMPLEXITY
|
||||||
|
https://www.youtube.com/watch?v=jVL4st0blGU
|
||||||
|
|
||||||
|
1. Memorise less!
|
||||||
|
- Less burden to, even starting the game
|
||||||
|
- Start with gentle learning curve, getting slowly steep
|
||||||
|
- Intuitive UX (UI, control, ...)
|
||||||
|
- Good tutorial = lessens complexity
|
||||||
|
|
||||||
|
2. Intuitive!
|
||||||
|
|
||||||
|
3. Calculations per second
|
||||||
|
- reduce!
|
||||||
|
|
||||||
|
4. Players have to know everything to even begin the play ### FAIL (irreducible complexity)
|
||||||
|
- Make them get familiar with rules of the game
|
||||||
|
- Dwarf Fortress failed this!
|
||||||
|
|
||||||
|
|
||||||
|
## Lots of things players can play with (aka don't make them bored)
|
||||||
|
|
||||||
|
- Combat, battle, building, mechanics, adventure, dungeon explore, spelunking
|
||||||
|
- Not scaled; easy combat, tough combat, tedious combat, etc.
|
||||||
|
|
||||||
|
|
||||||
|
## Achieving perfect imbalance
|
||||||
|
https://www.youtube.com/watch?v=e31OSVZF77w
|
||||||
|
|
||||||
|
- Make sure no matter how you skilled, your playable character cannot be good at everything
|
||||||
|
- Give players __wide pool of options__ to solve problem
|
||||||
|
(kill the boss, defend their adobe, fast transportation, etc.)
|
||||||
|
|
||||||
|
|
||||||
|
**_What feeling do you want to convey?_**
|
||||||
|
|
||||||
|
|
||||||
|
## Always think WHY you want to add _something_ on the game
|
||||||
|
|
||||||
|
- e.g. Why are you adding RPG leveling system? What it would do to the players? How would they play with?
|
||||||
|
|
||||||
|
|
||||||
|
See also: *HEARTS, CLUBS, DIAMONDS, SPADES: PLAYERS WHO SUIT MUDS*
|
||||||
Reference in New Issue
Block a user