Perilar: Dark Weaver

Perilar was my favorite of my games, an original iPhone RPG (loosely inspired by Rogue, Ultima, & Zelda). Alas, the App Store is a pain in the ass to stay current in, and Perilar needed updates I wasn't willing to jump thru Apple's hoops to deliver, so it's been gone from the store for a few years. Does anyone even remember me?

Then I wrote & released Brigand, a stripped-down realtime roguelike, which apparently everyone got mad at either because it was too hard (it was, but I liked that), or cost $9.99 which is SO MUCH MONEY on the goddamned App Store. And again the App Store made it obsolete and it wasn't reasonable to update it.

So I got back to a new desktop version of Perilar. I wrote a JS prototype (Fallen Kingdom) that wasn't fast enough to be usable, but let me rapidly test a bunch of new things. Now in Scheme, after a very long time, I have a nice, fast, nearing-complete sequel to Perilar: Dark Weaver.

Where I am right now:

  • World has both hand-designed and random sectors, tho the latter need some smoothing out to look like real terrain. I can walk across the world, at least until I hit impassable sectors. Porting my complex map and dungeon generators in is the next task. I have spent the last 6 months building features in the Town of Amity, and I'm ready to move on!
  • Most of the tile art is from the DawnLike set, with a lot of customization and new art where needed, and I've stuck to the DawnLike palette, it really has a nice old-timey look, a little less garish than the Atari 800, brighter than C64.
  • Player art isn't going to be these sprites, but the paperdolls I have are 2-facing (East/West), and I'd prefer 4- or 8-facing (you can move diagonally!); so I still need to find or draw (oh no) those.
  • NPCs have dialogue trees, stores, and special abilities (like the Innkeeper healing you; they're not super-powered).
  • Combat, with multiple attack/defense options, works in my test area. I haven't spread monsters around the sectors yet, but they've been developed and tested in the JS prototype.
  • Loot is extensive, magical weapons and armor have all the complex options you'd expect. I'm being a hardass on encumbrance in this one, because you can drop loot anywhere and come back for it. (Not quite the hardest possible ass; gold doesn't count towards weight, which it does in tabletop RPGs!)
  • Spells beyond Magic Missile are not implemented at all yet; will probably ship with only the dozen basic spells from the original release, and advanced spells added in an update. You won't find anyone to teach those for a long time anyway. Despite that, Wizards are still useful with magic wands.
  • New bosses, boss arenas, deeper dungeons, main quest, and sidequests.
  • At least one sector will be user-modifiable, tho I don't know if it'll be in the first release. You can buy furniture and walls, and fix up your own town. There's useful things you'll be able to get from that. (The building mechanic half works now; gathering doesn't).
  • Currently tested on Mac, should be buildable with no or very few changes to Windows, Linux, BSD, etc., but I need to get proper test environments for all of those.
  • Will be for sale on itch.io sometime this year. Price TBD.

I feel super awkward about self-promotion, but I do have a Patreon, and for Gold level you'll get betas; I haven't explained this, but at any level, when you've paid up whatever the cover price of the game ends up being, you'll get a full release license for it, too.

darkweaver-2020-01-08-2
darkweaver-2020-01-08-3

Software Principles for 2020

This is both for myself, and to decide what software I'll tolerate in my presence in the future.

  1. No lag. All UI must respond and be responsive again within 100ms. Most everyone has many cores in their CPUs and a massively parallel GPU not doing that much, you can spare ONE to run your work thread. Stop with the long animation shit. 100ms is plenty to see a shadow moved from one place to another, where there is now an interactive UI.
  2. No load screens. If you can't preload "instantly", be functional, show a usable menu while background loading. Media streaming needs to buffer, but you can show a poster frame instead of empty space.
  3. No ads or spyware. If you can't subsidize your software some other way, don't ship software. Or as the late very lamented Bill Hicks said, "If anyone here is in advertising or marketing, kill yourself!" (and of course there's ads on youtube; so maybe I need to find a better video hosting system? I know there's a fediverse-based video thing)
  4. No custom binary formats. Save your data in JSON or some other common system (plist on Mac, etc), so users can export & manipulate it from their own tools.
  5. No sites without syndication. If you have a web site or blog, you MUST support RSS or Atom, or both. Failure to do so should have you removed from the Internet.
  6. No unsecure connections. I know it's hard to add https the first time, and some older services can't be easily wrapped, but every http connection is a chance for false information to be fed to you, your computer compromised, your information to be stolen.

Atheism Reading Assignment

The things that deconverted me as a child:

  • National Geographic Concise History of Religions: Either one of these is right, and it's not yours, or none of them are right. I'm particularly fond of the Aztecs, since they believed at a depth no rational person can comprehend… and were just totally wrong. Huitzilopochtli didn't end the world when the sacrifices stopped.
  • Carl Sagan's Cosmos, book (most importantly) and TV series (often streaming online, or get the boxed set). Explains the scientific method, and how we have learned what we know. I don't recommend Neil Degrasse Tyson's version, which is much more pop-culture.
  • Isaac Asimov's Guide to the Bible: Explains where the Bible came from and how it was written, and why.

Additional:

Adult Engineer Over-Optimization as the Motie Problem

Looking at my Scheme code and the way I customize it, I'm starting to see the real reason evil megacorps (and wannabe evil startups) won't hire even middle-aged programmers or use your favorite weirdo language, they just want young idiots who code Java or Go.

If you think about a standard software career, there's maybe 10 years of a submissive fool badly coding crap languages ^1 like Java, Go ^3, PHP, JavaScript ^4. They just got out of college or self-trained, and can barely copy existing algorithms, let alone think of one for themselves. This is why FizzBuzzTest ^5 is such a good novice coder test: It requires following directions exactly, and slightly competent logic skills, but not much more.

Then maybe 10 years of them being project managers and "architects", running waterfall and GANTT charts; they'll say they're "agile" but then have a giant JIRA repo of "backlog" features which have to be implemented before shipping, weekly 4-hour planning "backlog grooming" meetings, and unrealistic estimates. This is sufficient to build all kinds of horrible vertical prisons of the mind like Azkaban Facebook.

Then they either retire, or are "downsized", and now what? So they work on their own code, do maintenance on old systems, or leave the industry entirely.

If they work on their own, freed of evil megacorp constraints, they're going to end up in something idiosyncratic and expressive, like Scheme, LISP, Forth, or a custom language. Make their own weirdo environment that's perfectly fit to themself, and unusable/unreadable by anyone else.

Case in point, I needed an object model. There's one I like in Gerbil, and Gerbil's blazing fast, but I can't make a full SDL2 library for it yet (Gambit's FFI is hard, I've hit some bugs, and there's a LOT of library to interface to), and I'm using a bunch of other Chickenisms anyway, so I can't really move to it yet. Instead I just made my own simple object libary, with a couple macros to hide the ugly reality behind it:

(test-group "Object"
    (test "Object" 'Object (class-name Object))
    (let [ (obj (@new Object))  (bug #f)  (cow #f)  (duck #f) ]
        (test "Object-to-string" "[Object]" (@call obj 'to-string))

        (define-class Animal Object)
        (define-field Animal 'legs 0)
        (define-field Animal 'color #f)
        (define-method Animal 'init (self legs color)
            (set! (@field self 'legs) legs)
            (set! (@field self 'color) color) )
        (define-method Animal 'speak (self)
            (sprintf "The ~A ~A with ~A legs says " (@field self 'color) (class-name (@class self)) (@field self 'legs)) )

        (set! bug (@new Animal 6 "green"))
        (test "bug-legs" 6 (@field bug 'legs))
        (test "bug-color" "green" (@field bug 'color))
        (test "Bug speak" "The green Animal with 6 legs says " (@call bug 'speak))

        (define-class Cow Animal)
        (define-method Cow 'init (self color)
            (@super self 'init 4 color) )
        (define-method Cow 'speak (self)
            (string-append (@super self 'speak) "MOO!") )
        (set! cow (@new Cow "brown"))

        ;; second class to make sure classes don't corrupt shared superclass
        (define-class Duck Animal)
        (define-method Duck 'init (self color)
            (@super self 'init 2 color) )
        (define-method Duck 'speak (self)
            (string-append (@super self 'speak) "QUACK!") )
        (set! duck (@new Duck "black"))

        (test "Cow speak" "The brown Cow with 4 legs says MOO!" (@call cow 'speak))
        (test "Cow to string" "[Cow color:brown;legs:4]" (@call cow 'to-string))
        (test "Duck speak" "The black Duck with 2 legs says QUACK!" (@call duck 'speak))
        (test "Duck to string" "[Duck color:black;legs:2]" (@call duck 'to-string))

        (test "instance-of?" #t (instance-of? cow Cow))
        (test "instance-of? parent" #t (instance-of? cow Animal))
        (test "instance-of? grandparent" #t (instance-of? cow Object))
        (test "instance-of? cousin-false" #f (instance-of? cow Duck))
        (test "instance-of? not an obj-false" #f (instance-of? "wtf" Cow))
    )
)

The implementation code's not much longer than the tests, but it's not quite done for me to show off; I need to switch my macros into non-hygeinic forms so I can get rid of the (self) in define-method, and introduce an Objective-C-like _cmd field for self-reflection, and message-not-understood handling. There's always more tinkering to do.

Which is great for me, but makes my code an undocumented (mostly) new language, unusable by anyone normal. A giant pile of crap Java program, no matter how old, can be "worked on" (more crap piled on top) by any teenage Bro Coder.

All of which brought to mind The Mote in God's Eye, where the Motie Engineers over-optimize everything into a tangled mess, and the Watchmaker vermin are even worse, wiring up everything to everything to make new devices. The threat posed by and solution to Scheme programmers, in your usual authoritarian megacorp scenario, is similar to Watchmakers.


^1 Swift is intended to fit this niche much more than weirdo expressive Smalltalk+C Objective-C was, BDSM ^2 to prevent one from writing "bad" code, but it's not there yet; the reality of low-level software dev can't be simplified as much as Apple wants, and their C++ developers weren't up to the task anyway.

^2 Bondage-Domination-Sado-Masochism; aka strict type systems and code flow analysis, that prevent one from writing "bad" code at the cost of annotating everything with types instead of doing useful work. I'm not kink-shaming people who do that for sex, only those who do it to their own software.

^3 Rob Pike has openly said they can't give a powerful language to newbie Googlers, they mostly just know Java, C, C++, which is why Go is so limited and generic.

^4 Oddly, JS is basically a LISP with really shitty syntax. It's easy to make trivial, broken junk in it, but it's also powerful and expressive if you're an old maniac who understands the Self-based object system.

^5 Oh, fine, but only so I can demonstrate something:

(define (fizzbuzz-test i n s)  (if (zero? (modulo i n))  (begin (display s) #t)  #f) )
(define (fizzbuzz i)
    (unless (any identity (list (fizzbuzz-test i 3 'Fizz) (fizzbuzz-test i 5 'Buzz)))  (display i))
    (newline) )
(for (i 1 100) (fizzbuzz i))

Totally different structure from the usual loop-if-else repetition and hardcoding of everything, because Scheme encourages coding in small pieces. Of course I wrote my own for macro which expands to a named let loop; there's many like it but this one is mine. More Motie engineering.

Programming the Atari 8-bit

My programming started in 1979 with the TRS-80 Model I, but in late 1981? early 1982?, I got my Atari 800, and later a 1200XL, then Atari ST. Those are what I consider "my computers".

Last few weeks for hobby time, I've taken up playing with an Atari 8-bit emulator, and may soon buy an old machine (130XE? I guess?) and a modern SD-card reader, and HDMI adapter unless I want to set up my old CRT… Yes, this is "pointless", but it's the most emotionally rewarding programming I've done in some time.

Had to do a lot of setup to get to this point, though. Follows are my excessive notes, which will hopefully be useful to others.

The keyboard mapping in AtariMacX is weird, I finally figured out:

Mac Key Atari Key
` Break
F2 Option
F3 Select
F4 Start
F5 Reset
Sh-F5 Cold Boot
Opt-F5 Insert Char (be REAL DAMN CAREFUL not to miss the Opt key!)
Sh-Opt-F5 Insert Line (same, DANGER WILL ROBINSON DANGER)
Home / Opt-F7 Clear
End Atari/Inverse
PgDn / Opt-F10 Help (XL/XE)
Opt-F1 F1 (1200XL)
Opt-F2 F2 (1200XL)
Opt-F3 F3 (1200XL)
Opt-F4 F4 (1200XL)
Capslock Cycle caps, may take several tries of caps A backspace repeat until you get lowercase, not graphics or uppercase.
Sh-Capslock Uppercase, almost always works

Typing on a real Atari keyboard is probably the #1 reason to get real hardware instead of emulation.

Immediately it comes rushing back, how much I didn't like the default environment of blue screen, clicky keyboard, inset margins. Easy to fix with a few pokes, but I don't want to do that every time I reboot, so I need a startup program.

  • First, configure Atari800MacX with the subdirectories next to it. It comes with all these folders in user space, but it's actually mapped to somewhere in /var, which is awful.
  • Make a boot disk. Media -> Disk Image Conversions -> XFD to ATR, pick the DOS25.XFD image in OSRoms, and call that boot.atr, store it in Disks, Load it in D1 Cmd-1 and pick boot.atr.
  • Reboot into DOS, by Control -> Disable BASIC. Bask in the glory of Atari DOS 2.5.
  • Make a data disk, Media -> New Floppy Image, I went with Medium Density (130K) since almost everything can read that, assign to Drive 2, and call that disk2.atr or whatever.
    • From Atari DOS, Format: I <return> D2: <return> Y <return>
    • Preferences -> Boot Media -> Set to Current Media, Save Configuration
  • My Atari BASIC project on Gitlab
    • Based on what I remember of my old main menu, I had a ton more stuff but I'm slowly adding routines as I need them. This can also be a shell for new programs, delete 11-9998 and use the subroutines. I wrote Draw to test joystick & function key scanning, not to be a good paint program, typed in a Music demo to make sure I had sound working.
      • Digression: This is not an efficient structure, because high line numbers take longer to find; an optimizing Poindexter would put the subroutines tightly packed at 1-999 and the program at 1000+, but it's massively easier to read & work with this way. I won't be in BASIC that much anyway, it's just for utility work.
    • Download AUTO.LST, convert Unix newlines (char 10) to the ATASCII newline (char 155 õ), and drop it in the HardDrive1 folder.
    • % LANG=C tr '\233' '\n' <AUTO.LST.TXT >AUTO.LST
    • Or you can just Media -> Edit an .ATR disk image, import file, and that has a newline conversion.
    • From BASIC, E."H1:AUTO.LST" <return> RUN <return>, pick Y. (Script AUTORUN.SYS), and enter:
      • ?"MAINMENU"
      • E."H1:AUTO.LST"
      • RUN
      • .
    • Change H1 to D1 if you saved it in your boot.atr.
    • Now it'll do that on every bootup from that floppy. Reboot to be sure it works.
    • If you make changes to your main menu, remember to LIST "H1:AUTO.LST". I use LIST/ENTER (text LST format) instead of SAVE/LOAD (tokenized BAS format) so I can read it from the Mac; BAS is slightly smaller and much faster to load/save, but it doesn't matter with emulation or an SD-card.

    • Atari-autorunsys

  • BASIC set up and tested, and it's a convenient place for little utilities, but now for real programming.

  • Atari Macro Assembler and Program Text Editor

    • Download this, read the fine manuals; more for MEDIT than the assembler unless you're really hardcore. I will probably do little or no assembly, even tho back in the '80s I could hand-assemble short programs directly into ATASCII codes to run from BASIC; bug-eating freak that I was.
    • Read the MEDIT manual. It's quite a respectable full-screen editor with command mode for search/replace, block editing, etc.
    • Open the Atari Macro Assembler and Program Text Editor.atx (ATX is write-protected or encrypted or something; you can't use them directly, and have to disable the SIO speedup hack in emulator) disk in drive 2 of your Atari (Cmd-2), Control -> Disable BASIC (which will reboot to DOS). So you want the program files off that:
      • DOS: C <return> D2:MEDIT,D1:MEDIT <return>
      • DOS: C <return> D2:MEDITCM.BAS,D1:MEDITCM.BAS <return>
      • DOS: C <return> D2:AMAC,D1:AMAC <return> (skip if you'll never write ASM)
      • DOS: C <return> D2:SYSTEXT,D1:SYSTEXT <return> (I think only needed for AMAC?)
      • Eject: Ctrl-Cmd-2
      • Reload your data disk, Cmd-1, disk2.atr.
    • Control -> Enable BASIC, LOAD "D1:MEDITCM.BAS" <return> RUN <return> and configure MEDIT however you like.
      • Language: PAS
      • Tabstops: Set at 5 and +4 after the existing ones, because 8-wide tabs are crazy in a 40-column screen. Yes, I'm a tabs not spaces guy, OBVIOUSLY.
      • Margins: 1,40
      • Colors: 12,4,14 (sadly can't be 0 or 2 background luminance, because the cursor is black)
      • Flags: Tabs: Expand, Shift-Lock: No (starts in lowercase).
      • Save & Return to DOS.
      • You can just copy the MEDITPAS.ECF to MEDITTXT.ECF, etc., you don't need to run the tool for each language, but it doesn't have a default mode. Note you also have to copy these to each disk you're editing on, or it switches back to the stupid defaults:
      • DOS: C <return> D1:*.ECF,D2: <return>
      • DOS: L <return> MEDIT <return>, filename D2:HELLO.PAS, and enter:
        program hello;
        var c: char;
        begin
          writeln('Hello, Atari!');
          read(c);
        end.
        
      • <option> exit <start> to save & exit. Note return doesn't execute commands in MEDIT, start does. Kids Today™ have some meme about how hard it is to exit vi? Ha ha, they have no idea. RTFM.

  • Finally ready to program in Action! or Pascal, which is what I mainly did back in the day.

    • Deep Blue C: Tragically underpowered version of Small-C. I loved it as an intro to C, but didn't use C for real until the Atari ST. It did produce standalone binaries and the compiler was easy to use, IIRC.
      UNSUPPORTED FEATURES
        Features in C not supported in DEEP BLUE C are:
        1) structures, unions
        2) multidimension arrays
        3) Floating point numbers
        4) Functions returning anything but int
        5) Unary operators: sizeof
        6) Binary operators: typecasting
      DIFFERENCES FROM STANDARD C
        THE DEEP BLUE C language has the  following nonstandard features:
        1. The last clause of a "switch" statement, either "case" or "default", must
      be terminated with a "break", a "continue" or a "return" statement.
        2. The ancient =<op> construct has been removed. Use <op>= instead.
        3. Characters are unsigned. Chars range in value from 0 to 255.
        4. Strings can not be continued on the next logical line.
        5. C source code lines can be a maximum of 79 characters long.
        6. Functions can have a maximum of 126 arguments.
      SPECIAL SYNTAX
        C uses several ASCII characters not available on the ATARI computer's
      keyboard. In particular the braces have been replaced by to two-letter
      combinations $( and $), and the tilde has been replaced by $-.  The $ character
      is not used in C, so your editor's find and replace command can be used to
      convert standard c programs into a format acceptable to DEEP BLUE C.
      
    • Action!: Custom language on cart for Atari, fantastic built-in editor (later the basis for the Paperclip word processor!), had a disk runtime system so you could distribute programs (also on AtariMania). But it came out a little later than my Pascal adventures, and it's a weird super-low-level language, and I think I'm in no mood to relearn it right now. Super goddamned fast, tho. May get into this if I'm frustrated later.

    • APX Pascal: Excessively complex process with a disk swap for every compile, compiles & links into PCode, no explanation of how to boot it. This is a very user-hostile compiler.
    • Kyan Pascal: Maze of command line tools. Doesn't work, at least for me, on emulation. It cycles through the tools, but never actually builds anything, eventually crashes and corrupts video. Makes a big deal of being usable from RAMDisk, but that doesn't matter on modern hardware.
    • Draper Pascal: Which I used in the '80s. Hilariously bad editor (but I can use MEDIT, so fuck that), compiler just fucking works, but only produces PCode (.PCD), so has to start from bootdisk or run Draper's menu then your program, ick. But this was no trouble to get running, so it wins.
      • Insert drpascal.atr in drive 1, reboot, boots into a menu.
      • 3 Compile program: D2:HELLO.PAS
      • 1 Run program: D2:HELLO
      • Total success! \o/ Hit any key to exit the program.
      • Drive 1, boot.atr, Drive 2, drpascal.atr, reboot
      • DOS: C <return> D2:AUTORUN.SYS,D1:PASCAL.COM <return>
      • DOS: C <return> D2:INIT.PCD,D1:INIT.PCD <return>
      • Cmd-2, disk2.atr
      • So now I can: DOS: L <return> PASCAL.COM <return>
      • And run Pascal programs. I could make a more focused runtime menu for it, maybe dir & list all the PCD files, the INIT.PAS source is included. If I ask it to compile, it prompts to insert drpascal.atr, and then I can switch back, which is reasonable.
      • Standard library is small but effective, seems like it has all the BASIC equivalent commands, and enough POKE/PEEK/ADDR stuff to let me do everything, including Player-Missile Graphics.
      • I can presumably now move all my source and disk2.atr contents to H1, so they can be managed & edited on the Mac, but I just wanted to get things running first.
      • Probably make another gitlab project (and actually sync it from git) when I get somewhere with that.

This took quite a lot of my hobby time doing something harder than actual work, to be honest. But I'm in a good place with it now.

A Scheme of Gerbils Runnin' in a Wheel

Chicken's mediocre performance is causing me problems, so I'm taking yet another language tour/spike.

Looking at Gerbil Scheme, as a faster Scheme and as a bonus it's closer to R7RS. It has far less library support than Chicken, but does have a FFI, and compiles to a native binary through C, so I really don't need too many libraries.

Instead of the #!key #!optional #!rest keywords used in Chicken and some others, Gerbil uses a literal template style for functions:

;; Chicken: (define (foo a #!key (b 'bar) #!optional (c "see?") #!rest rest)
;; Gerbil:
(def (foo a b: (b 'bar) (c "see?") . rest)
    (print "a=" a " b=" b " c=" c " rest=" rest "\n")
)
(foo "Mark" 1 b: "bees!" 'what) ;; note out-of-order optional & keyword
;; a=Mark b=bees! c=1 rest=what

I like this style better, but I dislike the "def" keyword (which uses the enhanced lambda that does this) instead of "define" which uses "lambda%" (traditional lambda).

Gerbil uses [] for list construction, and {} for method dispatch, so goodbye to the nicely distinguishable braces I was using in Chicken. The spec says implementations can do what they want with those symbols, but I wish they wouldn't. Ah, well. I'll add a shitload more whitespace and some comments and it'll be fine.

The struct/object system in Gerbil is pretty nice, they're slightly upgraded records, but there's an (@ obj field) syntax instead of (MyClass-field obj), and (defmethod {mymethod MyClass} ...) creates a polymorphic {mymethod obj args} which finds the right method for any object, which is especially useful for inheritance.

I tried doing some VT100 graphics just to proof-of-concept, but it's doing something to the terminal, such that the same escape codes which work in Python don't clear the screen fully in Gerbil. After a short losing battle with stty and termcap, I give up on that and I'll jump right to writing a C FFI to SDL, because in 2019 that's easier than writing to a console.

Daily reminder that everything we have made since 1984 is overcomplicated junk. On an Atari 800, this took a few seconds to type, and you could start coding a nice UI instantly:

atari-is-awesome-graphics1

Alas, we live in a fallen world, so this is going to be trouble. Here's my Gerbil FFI template so far:

package: myffi

(import
    :std/foreign
)

(export #t)

(begin-ffi
    ;; names of all Scheme wrappers to expose
    (chello)

(c-declare #<<CDECLEND

#include <stdio.h>

int chello(void) {
    printf("Hello this is C!\n");
    return 1;
}

CDECLEND
)

    (define-c-lambda chello () int "chello")

) ;; begin-ffi


; TODO for constants: (define FOO ((c-lambda () int "___result = FOO;")))

(define (main . args)
    (chello)
)

Gerbil has a Scheme-based build system, but I'm a caveman so I make another build.zsh:

#!/bin/zsh

function usage {
    echo "Usage: build.zsh MAIN.scm [LIBS] || -?"
    exit 1
}

if [[ $# -eq 0 || "$1" == "-?" || "$1" == "--help" ]]; then
    usage
fi

mkdir -p bin

main=`basename $1 .scm`

gxc -exe -static -O -o bin/$main "$@" || exit 1
echo "Built bin/$main"

Now:

% ./build.zsh myffi.scm
Built bin/myffi
% bin/myffi
Hello this is C!

Hooray! Unconditional success! Only took all afternoon and a half-pot of coffee!

Now I "merely" have to wrap all of SDL (well, just the parts I need) and get linking working and oh sweet merciless Cthulhu. And I still won't know how much this'll help my performance until I'm days into it. But, the first step is the hardest.

Y C?

C has the great virtue that most computers have a C compiler installed or can get one from the vendor, and by typing:

% clang -o thing thing.c # or gcc if you must.

You get a binary that'll run on that platform. If you wrote your code sanely, you can recompile it on every major platform with no changes. If you find a place where a platform's different, you can add #if to fix that.

Contrast with every other systems language:

  • Do you have a compiler installed?
  • Is it portable?
  • Can you even fix non-portable areas?
  • Can you make a binary an end-user can run?
  • Can you call other libraries?

In C, the answer is always yes. In any other, it's "probably not, or only with great effort".

Someone was recommending Ada. It's not in standard gcc. You have to install something called "GNAT":

% sudo port install gnat-gcc
#  Ada is self hosted (http://en.wikipedia.org/wiki/Self-hosting)  #
#  You need to install an existing Ada compiler and then choose    #
#  an appropiate variant. For more info use:                       #
#  port variants gnat-gcc                                          #
% sudo port variants gnat-gcc
gnat-gcc has the variants:
   ada: Uses the MacPorts Ada (https://www.macports.org/) compiler to bootstrap!
   gnatgpl: Uses GNAT/GPL compiler (http://libre.adacore.com) to bootstrap!
   gnuada: Uses the GnuAda (http://gnuada.sourceforge.net/) compiler to
           bootstrap!
   macada: Uses MacAda compiler (http://www.macada.org) to bootstrap!
   odcctools: Use the odcctools instead of the system provided ones - does not
              work for x64 currently!

I dunno what to do here. MacAda hasn't been updated since OS X 10.4, which was 2005. I don't see any other ada in MacPorts. At this point I gave up and uninstalled everything. It's not a working language.

Go is fine except that it's a statically-compiled Java owned by Google, and every part of that is evil and wrong. The Rust Evangelism Task Force's constant whining has made me unwilling to even give all those &'s a chance, they're like digital Mormons. There's nothing really wrong with D Language except that it's not installed anywhere, and it's no safer than C for a lot of extra typing.

C isn't safe, but it's fast. It's pretty hard to use safely on large projects, but for small tools with static data buffers it's fine. You take some tradeoffs for any language.

For high-level programming, I love Scheme and JavaScript, and there's a ton of other good high-level languages. But if you need to write at the lowest level, and make it work everywhere, C's the only rational choice.

Project UFO

Which one is correct? Let's think about this from the other direction. Could we buzz another planet, today, in a way that makes "UFO sightings are ALIENS!" make any kind of sense?

Premise 1: It is incredibly unlikely that any "intelligent" species, having recently developed from hunter-gatherers to agriculture to technology in the span of a few thousand years, is smart enough to reach that technological stage without making their planet uninhabitable as we have, or discovering nuclear weapons and waging primitive tribal warfare with them. Even if anyone survives this century, or we colonize Mars, it may be centuries before we have this amount of available energy and economy again.

Therefore 1: Any "UFO" is probably from someone like us, just barely capable of doing it before going extinct. A last fireworks show before the Long Night.

This is going to take a while to work out. Get a coffee.

The nearest star is Proxima Centauri, 4.3 Light Years (272K AU, or 40.7 trillion km) away, and there is a potentially habitable planet.

If we stopped having wars (as if!), we'd have a few trillion dollar surplus; but I'll just suppose we redirect no more than half our military budget. You could easily recruit volunteers for a life-long mission.

A spaceship capable of keeping people alive to get there would be, as a minimum, the size and complexity of a nuclear submarine, 6800 tons displacement, 128 crew, and maybe 100x the cost: $150 billion. Let's handwave away with hydroponics and recycling that a real sub has to surface for supplies every 3 months, and the reactor lasts 30 years before it needs a refuel from recently-processed uranium. Neither are insurmountable engineering, the ship's going to be unpleasant to live in but it's about the best we can do.

SpaceX Falcon Heavy can lift 22.2 tons to orbit, displacement isn't exactly dry weight but close enough for an estimate so that's 300 launches at $100M+ each ($30 billion!) and then somehow assemble it in orbit.

Assembly would be easier if we had a space colony, with a giant machine shop, or even could still run the Space Shuttle (the space truck finally useful for something!), but that'll cost even more money and time to set up. At least another $1 billion on moving enough workers through ISS to finish the thing.

Now we need a space drive. Here we're kinda screwed.

As reference, see Atomic Rockets, menu at the bottom of the front page is where all the interesting stuff is, and in particular Slower Than Light. And a lot of the systems given there don't work in reality, or we don't have yet.

The "ALIENS!" enthusiasts are gonna say magic spacedrive, or fusion torch, or whatever, but we can't make any of those, and fuel's still not adequate for constant burn. You can't magic up extra fuel. There is no such thing as faster than light travel. And see premise 2 later.

Bussard Ramjets would be perfect, even with the 0.12 C speed limit they would actually have… but we aren't within decades of making one.

The nuclear reactor could power an ion drive, which we know how to make and fuel, very very low thrust but constant acceleration, scratch pad shows decades to reach halfway and start decelerating, except we can't carry enough reaction mass and there's none in deep space. Great for in-system maneuvering if you're patient, useless for interstellar travel.

Orion drive, firing nuclear bombs at a heavy plate under your ass, is an act of war in our own Solar System, and a giant whiplash and cancer machine for the crew. 100% buildable, but nobody's that stupid.

Charles Pellegrino's Flying to Valhalla has a reasonable proposal for a sorta clean antimatter drive that'd get there in about 5 years, we just need to plate Mercury in solar cells to power particle colliders to make the shit. Avatar is a stupid, terrible, stupid movie, but Pellegrino designed the starship in it, which is perfectly reasonable. So, that's a century or two off. No good.

Solar sails and laser launchers should work, and we can make these. We'll know for sure in a couple weeks. Making them big enough for a huge ship (1000 km across!) is a challenge, but this is a matter of engineering, not fundamental science. This would take 20 years to reach halfway and 20 years to slow down, but some original crew and their kids could get there.

The lasers are the infinitely expensive part, where you can just sink all money forever into and not be done, but good news is A) they stay put in the Solar System, B) you can build and launch them one at a time over years as a satellite array zapping a lens which projects onto the sail, and C) they're useful anti-asteroid tools (not by burning, but put another sail on an asteroid, and you can push it out of harmful orbits). The bad news is D) the people back home may be dead/forget about you/not be able/be unwilling to continue running them in 20+ years, and E) lasers in orbit can be turned against ground targets, almost literally a lightning bolt from "god" striking down your enemies. Quis custodiet…

Worst case is the lasers go quiet, and the laser sail ship becomes a much slower solar sail ship, which has to make a couple of slowdown passes at AC. If our recycling is good enough, maybe that works, maybe we die alone in the cold of space.

Now we're cruising slowly thru the system, find a habitable planet. We can't land the ship, but have a complement of drones that can fly into atmosphere. An unmanned drone could maneuver faster than any aircraft, and would even be hard for primitive radar to spot, just like our UFO stories.

But is there anyone there? Humans have existed for ~1 million years, about 5,000 of that civilized enough to be worth talking to, 100 years capable of radio, before probable nuclear or environmental extinction. Out of 3.5 billion years of Earth being a life-bearing planet so far, and maybe 6.6 billion years ahead where life can exist, that's a 1 in 2 million chance of there being anyone to talk to.

The ship would be very visible, with sails out decelerating in, it'd be the brightest object in the sky. If the autochthons have radio, they can be called; but we'd have already heard their broadcasts here on Earth. Maybe blinking lights to talk to a more primitive culture? Land a drone and talk over a radio speaker?

There's no easy way to land, abduct redneck autochthons, probe their cloaca-like entries, and return. Even if there was space for a couple Falcons as landers (strapped to the sides as maneuvering thrusters?), they'd need fuel to get back up. It may be possible to do a one-time water landing of the spaceship without killing everyone.

The only reason we would ever have gone there is to meet them and share information, tell them about our home and what we're like. Show them Pulp Fiction and The Ramones and Heinlein's The Green Hills of Earth. We wouldn't be trying to keep it a secret, even aside from the physical impossibility of hiding the spaceship. Nor would the aliens cover it up; no matter what they are, we'd be the most important new source of science, technology, and entertainment.

But landing presents political problems even with public disclosure, they might go to war over who "gets the Earthers", and possession is 9/10ths of interstellar law. Hopefully there's some competent diplomats. There's a lot more ways first contact can go wrong than anything in the flight. Really think very carefully before landing.

Colonization is difficult anyway, the atmosphere's not likely to be the mix we need, the native life may be digestible into basic materials (most life is probably CHON ) but will lack any vitamins; we'll need to keep eating hydroponics. We'd be immune to local viruses but might have no immune reaction to local bacteria & fungi equivalents, nor would any native life to ours. Staying in orbit or colonizing a barren rock is safer.

There will be no alien hybrids, no half-Vulcan Mr Spocks, and the aliens won't look anything like a Human with a latex mask. First, do you consider mating with chimps, crocodiles, squids, tulips, or…? No, stop, I don't wanna know! Baka! Ecchi!! But those are genetically related to us and yet no offspring is possible because we don't have enough compatible genes. If panspermia is real, actual aliens would be more distantly related than fungi, and if not then it would be like screwing a rubber toy.

Conclusion 1: Any plausible alien spaceship scenario is going to look almost nothing like the UFO contact stories. We'd see them coming. They'd have to talk to us on the radio. No secret bases. No abductions. They'd be weird alien pop stars with agoraphobia and unused to gravity, constantly on PR tours and eating alien food because ours is useless.

Premise 2: So Pellegrino's matter-antimatter drive? The point of Flying to Valhalla was that a near-C space drive is a one-shot planet-killing weapon. You'd briefly see an X-ray burst, then the ship's front shield would shatter like a shotgun shell so you can't just redirect it, then the planet would explode, in the space of hours or minutes as the ship chases up behind its light. And you could set one up with a deadman switch to kill whoever killed your planet.

Therefore 2: We're not dead yet, and nobody's contacted us to say "listen up, these are the rules!" Mutual assured destruction means they have to assume we'll do it to them. They don't have to fire first, just make sure we know the threat exists.

Conclusion 2: Nobody within 50 light years of us has advanced technology and has heard our radio signals (50 years there, 50 years for the weapon to come kill us).

Any other scenario isn't science, isn't even science fiction, it's just fantasy. I like fantasy as much as the next guy who isn't wearing a My Little Pony shirt, but it's not real.

The Machine Stops

The problem with the Internet… and here I'm referring to (sweeps hand across everything in view) all of this, but to take just current events Google blocking ad-blockers in Chrome, Google downtime locking people out of their Nest thermostats and "Home"-controlled security systems, horrible prisons of the mind like Twitter and Facebook, and the cacophony of Fediverse drama over Eugen adding features (better features are already in Pleroma and glitch-soc Fediverse servers), Gab forking Mastodon, client devs making unilateral decisions to block domains despite helpless users complaining, or anyone having "free speech" (which Eugen in particular is opposed to; I strongly advise against using mastodon.social, find another instance). These are just a point-in-time examples, it's been going on for decades (oh, USENET, how we don't miss your flamewars) and will only end with us.

… is people using software they didn't write themselves. No understanding, education, or discipline required. Just install something and it works! It's a product, not a skill! But they don't know how, or why, or why they should not.

"It didn't take any discipline to acquire", in the words of Ian Malcolm/Michael Crichton.

Until the software they rely on shuts down, literally like E.M. Forster's "The Machine Stops", and then weak unskilled mole-people crawl out of the wreckage of machines they never learned to understand, make, or repair, and then die.

My solution is drastic but logically unavoidable: No more software installs. As a child, you get a bare machine with nothing but a machine-language monitor. You learn ML first. You type in a language compiler or interpreter. You build up your own tools. We return to type-in program listings like Compute!, but no binary blobs, it must all be readable, comprehensible source, with design and implementation documentation.

If you want to share software, you need to build up your toolchain to that point yourself. Hopefully by then you've learned to read all patches you install.

Should this be extended to all technology? Information technology has the unique ability to coerce how and what you think; an automobile or an antibiotic does not. There's an argument (in "The Notebooks of Lazarus Long", for instance) that a citizen should be able to make all their own things, "specialization is for insects". But insects are the most successful clade on Earth, and will long outlive us; some specialization is probably acceptable, as long as it's not in the part that controls how you think.

I don't think this civilization can ever do that, it will not make hard changes that inconvenience anyone. I think this horrible Machine will lumber on a few more decades and then we'll all die from it. But maybe isolated tribes will survive, or intelligence will arise in the Machines, or in a few million years another intelligence will evolve, and build new things the right, responsible way. Their history books will describe us as being as foolish and self-destructive as the Easter Islanders.

Support Me on Patreon!

With the BBS going public, and soon a real release of Perilar Fallen Kingdom, it's time for you to help me keep doing this!

Become a Patron!

I'd at least like to get my hosting costs under control, and anything over that goes to me making cool games and apps for art, instead of boring things to survive.