Temple of The Roguelike Forums

Development => Programming => Topic started by: tuturto on July 16, 2014, 06:48:18 AM

Title: LambdaHack
Post by: tuturto on July 16, 2014, 06:48:18 AM
I have been learning some Haskell recently and wanted to start writing something more complicated. There's engine called LambdaHack (https://github.com/LambdaHack/LambdaHack) that is used at least in Allure of the Stars (https://github.com/AllureOfTheStars/Allure). So, there are at least two examples how to use the engine, but is there a tutorial or something somewhere? Or other games written with the same engine?
Title: Re: LambdaHack
Post by: tuturto on July 17, 2014, 06:21:17 PM
I got LambdaHack compiled and running (not that difficult actually) with GTK interface. I have been picking around the source code and getting familiar with the layout. Nice thing is that the code is really well organized and looks sane. Maybe the best course of action is to copy the example game and start trying to change it a bit.
Title: Re: LambdaHack
Post by: tuturto on July 18, 2014, 07:49:13 AM
Currently I have a game up and running that uses LambdaHack as an engine. Configuration\actual exe is from a separate package (although code for that is still from the LambdaHack example). The biggest hurdle was to write .cabal file that specifies what libraries the game depends on and what extensions should be turned on.

So, there's a self contained software project that results a runnable game and depends on LambdaHack engine. Next step is to start picking it up and try to figure out how all the pieces relate to each other. I'm kind of thrilled, since I got a working game with user interface and all I have to do is to add the content :) Later on will have to look into actually extending things beyond what the engine offers.

Any ideas or hints, where should one start such a task? Any hints on Haskell (except the obvious one "learn to use it"). The language is really sweet and it's growing on me more and more.
Title: Re: LambdaHack
Post by: tuturto on July 19, 2014, 06:53:34 PM
Here's a screen shot just a moment before quine manages to kill the captain and the game ends.

(http://i.imgur.com/l7w8Jyyl.png) (http://imgur.com/l7w8Jyy)

Repo available at: https://github.com/tuturto/space-privateers (https://github.com/tuturto/space-privateers)

The engine supports having multiple units under command of the player. So far it looks to me that only one of them is moving at any given time, while others just stand still. I have been wondering if there exists a way to make them move autonomously and follow the player and fight when given a chance.
Title: Re: LambdaHack
Post by: Man of Letters on July 27, 2014, 09:15:03 AM
Hi! Just stumbled upon the thread...

Any hints on Haskell (except the obvious one "learn to use it"). The language is really sweet and it's growing on me more and more.

True. Here is a sensible prioritized list of Haskell resources

https://github.com/bitemyapp/learnhaskell

But nothing beats jumping headfirst into an alien codebase, obviously. ;)

So, there are at least two examples how to use the engine, but is there a tutorial or something somewhere? Or other games written with the same engine?

No tutorial and moreover the engine changes all the time (though the API
should be more stable after 0.2.14 was released yesterday). AFAICT, you are the first
brave (or mad) enough soul to use it and to announce the foolhardy attempt beforehand.

BTW, congratulations on choosing the cleaner, but harder, way of using
the engine, namely by keeping your game content in a separate Haskell package
from the start. I've modified the game docs to address that such noble
and audacious possibility even exists:

https://github.com/LambdaHack/LambdaHack/commit/d3d31fcb3fbf0d2110905ab534ab8797b3ae6f5b?short_path=04c6e90#diff-04c6e90faac2675aa89e2176d2eec7d8

Here's a screen shot just a moment before quine manages to kill the captain and the game ends.

Heh, YASD. Nice. :)

I see your dungeon has Hack/Nethack style visuals. For comparison
here is the Moria/Angband style (particularly the last screenshot)
that Allure of the Stars uses:

http://www.roguebasin.com/index.php?title=Allure_of_the_Stars

The engine supports having multiple units under command of the player. So far it looks to me that only one of them is moving at any given time, while others just stand still.

Yep. By default humans move one by one, and only melee simultaneously.
You can switch among the actors you control with Tab and Shift-Tab.
And if you really want to move a group together in formation,
you can select them with '=' or '_' and then run (Shift-direction).
Note however that they move one by one and each individual move takes a turn.

I have been wondering if there exists a way to make them move autonomously and follow the player and fight when given a chance.

By default monsters (aliens, robots, animals) do that. There's nothing stopping you
from adjusting your human faction to move like that or creating yet another
faction with this behaviour. Just tweak this line (from the 0.2.14 codebase)
to assign 'allSkills' to a non-leader actor:

https://github.com/LambdaHack/LambdaHack/blob/7e0776face9d4f0fbe8743b75da6067d3c7deb80/GameDefinition/Content/FactionKind.hs#L27

Or you can set 'meleeAndRanged' and then the heroes will remain immobile,
but will be able to reaction-shoot (or rather reaction-throw) all the time.

Have fun creating your world and eventually hacking the reality engine itself! :)
Title: Re: LambdaHack
Post by: tuturto on July 28, 2014, 01:11:41 PM
Hi! Just stumbled upon the thread...

Any hints on Haskell (except the obvious one "learn to use it"). The language is really sweet and it's growing on me more and more.

True. Here is a sensible prioritized list of Haskell resources

https://github.com/bitemyapp/learnhaskell

But nothing beats jumping headfirst into an alien codebase, obviously. ;)


That's actually the list I'm currently working my way through. Still at the very beginning of course, but far enough that I want to start digging around some real code.

BTW, congratulations on choosing the cleaner, but harder, way of using
the engine, namely by keeping your game content in a separate Haskell package
from the start.

It's always nice to be able to stand on the shoulders of a giant and use code that has been built before. I suspect that in the long run this way will be easier, since I can update the engine I'm using when you release new versions. Haven't had time to do that with the latest release yet, but it's on my list of things to do.

Here's a screen shot just a moment before quine manages to kill the captain and the game ends.

Heh, YASD. Nice. :)


Here's a short video of the current game: https://www.youtube.com/watch?v=PzyTw1g65Lg It's still quite similar with the LambdaHack, but I'm slowly working my way through how game content is defined and what kinds of tricks the engine can do. I should for example change the UI a bit, so it doesn't look like a direct copy of LambdaHack. As you showed with Allure of Stars, this is possible.


I have been wondering if there exists a way to make them move autonomously and follow the player and fight when given a chance.

By default monsters (aliens, robots, animals) do that. There's nothing stopping you
from adjusting your human faction to move like that or creating yet another
faction with this behaviour. Just tweak this line (from the 0.2.14 codebase)
to assign 'allSkills' to a non-leader actor:

https://github.com/LambdaHack/LambdaHack/blob/7e0776face9d4f0fbe8743b75da6067d3c7deb80/GameDefinition/Content/FactionKind.hs#L27

Or you can set 'meleeAndRanged' and then the heroes will remain immobile,
but will be able to reaction-shoot (or rather reaction-throw) all the time.

Nice, I will try that and see what happens. What about if I wanted to write a completely new AI for some actors, how should I approach that? I would like to have some monsters that don't explore the level, but remain within a room and sneak by the walls.
Title: Re: LambdaHack
Post by: Man of Letters on July 28, 2014, 02:21:58 PM
Quote
Here's a short video of the current game: https://www.youtube.com/watch?v=PzyTw1g65Lg

Yay, fun, you've beaten me to it. Heh, it's great to be surprised by the game's content for a change (being surprised by unintended consequences of my own content does not quite count ;) ). I'd love to play-test the engine using your game.

It's also great to see how people new to the game play it. E.g., you wisely keep you team members mostly together (except for some solo exploration missions), but usually not too close (danger due to grenades in newer versions). I wonder if you use running (it's not clear from the video, but I suspect you don't)? It's done via Shift-direction. If you use the numeric keypad, Num Lock may need to be (de)pressed. Running is good, because when a monster is spotted, running stops, so there is no risk of one-keypress-too-many YASD. When there is mouse support, running will be easier (just point and click), but for now I wonder if the first help screen should spend more words pointing it out or if something doesn't work well enough.

Quote
What about if I wanted to write a completely new AI for some actors, how should I approach that? I would like to have some monsters that don't explore the level, but remain within a room and sneak by the walls.

That sounds like a proper engine extension. We'd need to open a github issue and brainstorm a bit at our leisure. E.g., what if there are no rooms on the level? What if the monster is generated in a corridor? What is the story explanation for the behaviour? E.g., does the monster fear dark and only stays in lit rooms or does it remember it's birthplace and never goes beyond it's small territory? Or is it an intelligent assassin? But if so, shouldn't it rather hide in dark corridors? Or always try to keep out of melee range (I think monsters that don't melee already do that) or always try to stay not visible (AI already sometimes drops lights sources to ensure that, but it could also try to actively look for shadows). Etc.

Anyway, sounds like the module Game.LambdaHack.Client.AI.PickTargetClient would be involved. The bad news is that it's a rather dirty piece of code and that the whole target picking will be overhauled. The good news is that it should be a relatively simple change. You prepare it in your fork of the engine, make a pull request, I accept it and we are done.

You could define something close by removing the AbTrigger ability from the actor kind's skillset. The ability is responsible, in particular, for opening doors. So if the monster is generated within a room where all exits have doors (most rooms are like that --- you can control it via content on a per-cave-kind basis), it will remain in the room until another actor opens the door. A more brutal tweak is to remove the AbMove, which makes the actor immobile (except that it can exchange places with others; remove AbDisplace to disable that as well).

P.S. If we decide the feature is too specific/heavy/silly for the generic engine (very unlikely ;) ), you can also add it locally when tying the knot of the Main module of your game, by overriding some modules from the library. It's *much* more work than adding such a feature to the engine itself and we'd need to expose and generalize some more of the engine internals (which is a good idea, anyway), but it is and should be possible. This is an engine library, not a black box proprietary engine, after all.
Title: Re: LambdaHack
Post by: Man of Letters on July 29, 2014, 10:13:28 AM
BTW, I said that the game content API should be more stable after the 0.2.14 release, but I lied. I've just rewritten and simplified the Player (team capabilities definition) component of ModeKind (game mode definition) and it will still undergo minor changes in the next few days. Other than that I hope to keep the API stable and focus on the internals. The blame goes entirely to tuturto for his inspiring comments.

So, for development I'd advise to use the master branch of the github repo instead of the official release. I push only mildly tested things to master, plus there is the continuous integration via travis, so that should be fairly safe. As for catching up with the change in the .cabal file, the whole file can be safely copied from the Allure of the Stars repo, which is kept in sync with LambdaHack. I plan to publish the next release (and perhaps a couple after that) fairly soon (a month or two apart, I guess).
Title: Re: LambdaHack
Post by: tuturto on July 29, 2014, 11:23:04 AM
I have upgraded to the latest version of LambdaHack and the game starts. Still need to play around a bit and see that everything is still working as I would it like to work. I must say that doing the upgrade taught me quite a bit more about how the system is laid out, since I had to modify multiple files and dig out what the changes were and how I could incorporate them into my game. Now that I have the newer version of the engine, I can add more varied content too, which is a big bonus.

It's also great to see how people new to the game play it. E.g., you wisely keep you team members mostly together (except for some solo exploration missions), but usually not too close (danger due to grenades in newer versions). I wonder if you use running (it's not clear from the video, but I suspect you don't)? It's done via Shift-direction. If you use the numeric keypad, Num Lock may need to be (de)pressed. Running is good, because when a monster is spotted, running stops, so there is no risk of one-keypress-too-many YASD. When there is mouse support, running will be easier (just point and click), but for now I wonder if the first help screen should spend more words pointing it out or if something doesn't work well enough.

I'm aware of the run option, but haven't gotten used to it yet, I guess it's mostly just a habit. It certainly makes it harder to make one step too many, like I often too. Especially when playing with a squad of privateers. The first help screen explains it sufficiently well I would think.

That sounds like a proper engine extension. We'd need to open a github issue and brainstorm a bit at our leisure. E.g., what if there are no rooms on the level? What if the monster is generated in a corridor? What is the story explanation for the behaviour? E.g., does the monster fear dark and only stays in lit rooms or does it remember it's birthplace and never goes beyond it's small territory? Or is it an intelligent assassin? But if so, shouldn't it rather hide in dark corridors? Or always try to keep out of melee range (I think monsters that don't melee already do that) or always try to stay not visible (AI already sometimes drops lights sources to ensure that, but it could also try to actively look for shadows). Etc.

Anyway, sounds like the module Game.LambdaHack.Client.AI.PickTargetClient would be involved. The bad news is that it's a rather dirty piece of code and that the whole target picking will be overhauled. The good news is that it should be a relatively simple change. You prepare it in your fork of the engine, make a pull request, I accept it and we are done.

I'm interested in this, because I would like to create varied creatures, which behave differently. In pyherc, I have rats and beetles, that behave in a similar way. Both have their preferred areas, where they patrol around and when player comes too close, they will attack.

Like, for rats I define AI like this (parens warning):
Code: [Select]
(defn patrol-area? [level location]
  "rats prefer rooms"
  (and (next-to-wall? level location)
       (not (corridor? level location))))

(def rat-act (patrol-ai patrol-area? 4))

And for beetles just (they have slightly worse eye sight than rats, thus 3 for detection range):
Code: [Select]
(def beetle-act (patrol-ai open-area? 3))

patrol-ai takes care of actual logic needed for moving into patrol area, moving around there and attacking possible threats. I just create suitable versions of it by feeding a function to it that can tell what the patrol area actually is. Nice thing is that if there is a big room with couple of rats and beetles, they will patrol different areas. Skillful player might be able to sneak around them without being detected, but a mistake will cause them to attack him.

P.S. If we decide the feature is too specific/heavy/silly for the generic engine (very unlikely ;) ), you can also add it locally when tying the knot of the Main module of your game, by overriding some modules from the library. It's *much* more work than adding such a feature to the engine itself and we'd need to expose and generalize some more of the engine internals (which is a good idea, anyway), but it is and should be possible. This is an engine library, not a black box proprietary engine, after all.

I think this would be a good approach. Even if the engine would contain some basic AI routines in itself, other developers might want to roll out their own specific AIs for unique creatures. I'll tinker around a bit and try figure out things a bit before opening a ticket in github. Development will be slow in any case, because I'm still learning how the language is supposed to work :)
Title: Re: LambdaHack
Post by: Man of Letters on July 29, 2014, 01:18:15 PM
I have upgraded to the latest version of LambdaHack and the game starts.

Oh, great, then don't bother looking at the master branch in the github repo. The next release will come rather soon anyway.

Quote
I'm interested in this, because I would like to create varied creatures, which behave differently.

OK, that would probably mean the creatures have to be from the animal faction. That's because the monster faction (the dungeon defenders faction) is a playable faction and so the AI is supposed to emulate a human playing the faction. And a human would not patrol a room, but explore for loot and then wait for some team members to spawn or gather and attack in a group. Currently, the animal faction chases enemies, if visible, and otherwise just dumbly walks around --- this should be made more varied and interesting indeed.

Quote
In pyherc, I have rats and beetles, that behave in a similar way. Both have their preferred areas, where they patrol around

OK, sounds good: find a suitable territory and patrol it. Some real life animals do that.

Quote
and when player comes too close, they will attack.

OK, so that's another needed extension: an aggressiveness flag for an actor kind. Currently AI usually tries not to melee if there are no other team members close.

Quote
       (not (corridor? level location))))

That's another needed extension: we have to define what a corridor is, e.g., in a checker-board room, is every empty tile a corridor tile?

Quote
And for beetles just (they have slightly worse eye sight than rats, thus 3 for detection range):

That's OK, sight range is already implemented.

Quote
patrol-ai takes care of actual logic needed for moving into patrol area, moving around there and attacking possible threats. I just create suitable versions of it by feeding a function to it that can tell what the patrol area actually is. Nice thing is that if there is a big room with couple of rats and beetles, they will patrol different areas. Skillful player might be able to sneak around them without being detected, but a mistake will cause them to attack him.

That's great. Sneaking around and stealth are welcome diversions from the usual hack and slash.

Quote
Even if the engine would contain some basic AI routines in itself, other developers might want to roll out their own specific AIs for unique creatures.

Indeed. There's one more possibility: when we implement some routines in the engine, we can then generalize and push them out to content --- have a per-game file with named Haskell AI subroutines and use them, by name, in other parts of the content, e.g., actors or places (rooms) (weak-willed animals in such a room behave according to that AI).
Title: Re: LambdaHack
Post by: tuturto on July 30, 2014, 08:37:17 PM
Quote
In pyherc, I have rats and beetles, that behave in a similar way. Both have their preferred areas, where they patrol around

OK, sounds good: find a suitable territory and patrol it. Some real life animals do that.

It could also be a robot that has been programmed to patrol an area, or an guard man, options are very wide depending on the theme of the game. The idea I'm after is emergent game play. Small and simple rules will create complex behaviour when mixed together.

Quote
       (not (corridor? level location))))

That's another needed extension: we have to define what a corridor is, e.g., in a checker-board room, is every empty tile a corridor tile?

In pyherc I have every location that has wall on two opposite sides (but not on any others) considered as a corridor. This has the flaw that bends are not corridors, although they should be. Could also be any location that has exactly 6 walls around it and free locations aren't next to each other.

Indeed. There's one more possibility: when we implement some routines in the engine, we can then generalize and push them out to content --- have a per-game file with named Haskell AI subroutines and use them, by name, in other parts of the content, e.g., actors or places (rooms) (weak-willed animals in such a room behave according to that AI).


This sounds like what I was after.
Title: Re: LambdaHack
Post by: tuturto on July 31, 2014, 04:41:17 AM
I was setting up factions and players and have couple of questions.

This is how player is defined:

Code: [Select]
playerHero = Player
  { playerName = "Space Privateers"
  , playerFaction = "hero"
  , playerIsSpawn = False
  , playerIsHero = True
  , playerEntry = -1
  , playerInitial = 3
  , playerLeader = True
  , playerAI = False
  , playerUI = True
  }

What does playIsSpawn, playerEntry, playerLeader and playerUI control?

playerIsHero I think is used to mark which player is controlled by human in the campaign mode? playerInitial is amount of actors initially in the game and playerAI sets if this player is controlled by AI or not I think?

On the other hand, when defining a faction:

Code: [Select]
hero = FactionKind
  { fsymbol       = '1'
  , fname         = "hero"
  , ffreq         = [("hero", 1)]
  , fSkillsLeader = allSkills
  , fSkillsOther  = meleeAdjacent
  }

fSkillsLeader and fSkillsOther are skill lists used by the leader (often controlled by the human player) and others in faction. But what significance does ffreq have?
Title: Re: LambdaHack
Post by: Man of Letters on July 31, 2014, 05:44:09 AM
Quote
The idea I'm after is emergent game play. Small and simple rules will create complex behaviour when mixed together.

Spot on.

Quote
I was setting up factions and players and have couple of questions.

This is how player is defined:

Each field is documented in

https://github.com/LambdaHack/LambdaHack/blob/v0.2.14/Game/LambdaHack/Content/ModeKind.hs

However, that's precisely the bit of content API that is changed for the next version
(in particular FactionKind is merged into Player, though the general principles mostly stay the same)

https://github.com/LambdaHack/LambdaHack/blob/LambdaHack_Content_API_v0.5.0.0/Game/LambdaHack/Content/ModeKind.hs

(The tag LambdaHack_Content_API_v0.5.0.0 marks the version with the API
that should remain stable for a couple more releases, up to and including version v0.5.0.0 of the engine.
Sorry again for breaking the API, the new version is already on master branch of LH and Allure and the content API types and comments
should not change until after v0.5.0.0 (the behaviour will change subtly, e.g., due to fixing bugs or to the follow-the-leader AI
override being fleshed out (now it only works sensibly for AI teams))).

Quote
What does playIsSpawn, playerEntry, playerLeader and playerUI control?

playIsSpawn marks dungeon dwellers and playerIsHero marks humans.
playerEntry is the level the initial actors of that player start on.
playerLeader marks if the team has a leader at all, which mostly just means
the faction is potentially playable (e.g., animals are not).
playerUI means the actions of the team are displayed on the screen

Quote
playerInitial is amount of actors initially in the game and playerAI sets if this player is controlled by AI or not I think?

Yes, exactly. If a player is both playerUI and playerAI, the AI aspect can be turned off with ESC (and on again with Control-Shift-a). Try it e.g., with 'make frontendCampaign", which is great for testing your game.

Quote
fSkillsLeader and fSkillsOther are skill lists used by the leader (often controlled by the human player) and others in faction. But what significance does ffreq have?

It lists the actor groups that constitute the faction. Each actor belongs to a few groups, listed in ifreq in ItemKindActor. (In the new API this is simplified and each player controls exactly one group.)

P.S. I forgot the most important bit: if a faction has a leader, then the level where the leader resides is active --- actors move on that levels. So, if you have hero, monster and animal factions and the last one doesn't have a leader, then actors move on the levels where the hero or the monster leader resides and so the two factions control which levels are active. The animal faction actors can move only as long as their level is visited by the hero or monster leader (or as soon as they spawn on a level with a leader --- spawning is controlled via cactorFreq field of CaveKind, actor groups are listed together with relative frequencies; cactorCoeff in the new API determines the absolute frequency of spawning).
Title: Re: LambdaHack
Post by: Man of Letters on August 01, 2014, 11:42:31 PM
The engine supports having multiple units under command of the player. So far it looks to me that only one of them is moving at any given time, while others just stand still. I have been wondering if there exists a way to make them move autonomously and follow the player and fight when given a chance.

I've just finished and pushed to master branch a basic implementation of the follow-the-leader AI. It can be enabled for a faction via foverrideAI in the new content API and will be officially available in the next release. The test 'make frontendSafari' uses it.

The standard AI, of the 0.2.14 release, keeps team members close only when the level is fully explored. Otherwise, it sends actors away to explore and gather loot ASAP, before monsters do. In the follow-the-leader AI, team members swarm towards the leader's target or, if target not set, towards the leader position. If they start fighting an enemy or if they stand on items, they will finish fighting/picking up before following the leader again. But they won't detour towards enemies nor items nor unknown tiles to explore. In the future, it may be interesting to mix the two AI somehow and, e.g., let team members detour towards interesting things in a given radius only.

So, now we have 3 AIs (the third one is used for leader-less factions, such as animals, and is rather dumb). It would be great to generalize and parametrise them somehow, to be able to toggle them on the fly, as well as to define them as content and use in actor, faction, room and other content definitions. This is ambitious, but rather standalone task, so I guess I will create an issue on github for it at some point. It overlaps significantly with only one other task: target pool (having a pool of targets for the whole faction and assigning them to actors continuously instead of, as it is now, each actor having an independently chosen and fixed target, leading to duplication of effort). Code quality should benefit a lot from adding this feature, too.
Title: Re: LambdaHack
Post by: tuturto on August 02, 2014, 04:33:28 AM
Lots of cool AI stuff..

That sounds really great. I like the idea that I don't have to move each and every member of the squad all the time. These changes should make playing much more fun I think.

In the meantime (using the latest release of LambdaHack) I have defined factions and players and started working on some items. There are couple grenades, that are basically just potions that one can't drink.

Then there's still levels, places, creatures and maybe even rules to define. And lots more content on everywhere.

Sorry again for breaking the API, the new version is already on master branch of LH and Allure and the content API types and comments
should not change until after v0.5.0.0 (the behaviour will change subtly, e.g., due to fixing bugs or to the follow-the-leader AI
override being fleshed out (now it only works sensibly for AI teams))).

No worries, evolving APIs are a normal thing. I'm looking forward on the new features the next version will have.

I'm hoping/trying to finish first rough version of the game in a week or so and upload it to Hackage. Should also look into prebuilding binaries, but I have access only to a Linux machine, where I can do building so it'll be somewhat limited. Windows binaries would be great, but maybe in the future.
Title: Re: LambdaHack
Post by: Man of Letters on August 03, 2014, 10:44:50 PM
In the meantime (using the latest release of LambdaHack) I have defined factions and players and started working on some items. There are couple grenades, that are basically just potions that one can't drink.

Then there's still levels, places, creatures and maybe even rules to define. And lots more content on everywhere.

I've just added (to branch master) a stricter validation of content and some crude text messages given
when the content is detected invalid. Should make the process less painful.

Quote
No worries, evolving APIs are a normal thing. I'm looking forward on the new features the next version will have.

I'm away 13--23 Aug, so I think I will release LambdaHack 0.4.9.0 a couple days before I go.
If you base your release on that version,  you can state "LambdaHack >= 0.4.9.0 && < 0.6.0.0"
in your .cabal file, because the content API won't break till 0.6.
But "release early, release often", so you may as well release a version based on 0.2.14
--- it's relatively stable as far as I can say so far.

Edit: Actually "LambdaHack >= 0.4.9.0 && < 0.5.1.0" is safer, but the interval should still take
many months and quite a few versions of LH.

Quote
I'm hoping/trying to finish first rough version of the game in a week or so and upload it to Hackage.

Splendid, whenever it eventually happens. You may wish to announce that on "New Roguelike Releases"
and "Recently Updated Roguelikes" on http://www.roguebasin.com.

Quote
Should also look into prebuilding binaries, but I have access only to a Linux machine, where I can do building so it'll be somewhat limited. Windows binaries would be great, but maybe in the future.

I have the previous Ubuntu LTS (12.04.4), so I can build binaries for you there.
I wonder if it makes sense to try and build statically linked binaries for download.
Normally, with GHC 7.8 I get binaries that are reported by `file` like that:
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped

Quote
Windows binaries would be great, but maybe in the future.

I haven't yet figured out cross-compilation on Windows nor OSX (not sure if anybody tried the latter), so I can't help with that.
Title: Re: LambdaHack
Post by: tuturto on August 05, 2014, 09:46:59 PM
In the meantime (using the latest release of LambdaHack) I have defined factions and players and started working on some items. There are couple grenades, that are basically just potions that one can't drink.

Then there's still levels, places, creatures and maybe even rules to define. And lots more content on everywhere.

I've just added (to branch master) a stricter validation of content and some crude text messages given
when the content is detected invalid. Should make the process less painful.

This is always nice. While the current messages aren't always very clear, they are really helpful while developing a game. It's much easier to test things when possible problems are reported on a start up and not when the problem actually might occur.

Quote
Should also look into prebuilding binaries, but I have access only to a Linux machine, where I can do building so it'll be somewhat limited. Windows binaries would be great, but maybe in the future.

I have the previous Ubuntu LTS (12.04.4), so I can build binaries for you there.
I wonder if it makes sense to try and build statically linked binaries for download.
Normally, with GHC 7.8 I get binaries that are reported by `file` like that:
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped

Static ones would be easier for end users. With dynamic ones there's always the chance that the system where game is being run has incompatible libraries. I looked briefly into building a static version and added following to ghc options:
Code: [Select]
-static -optc-static -optl-static
In the linking phase, I got following errors:
Code: [Select]
Linking dist/build/SpacePrivateers/SpacePrivateers ...
/usr/bin/ld: cannot find -latk-1.0
/usr/bin/ld: cannot find -lgdk_pixbuf-2.0
That's of course because neither of those libraries are shipped with static versions by default (I'm running Ubuntu 14.04). Probably next step would be to compile static versions and use those while linking the game. I'm not going to pursue that right now, but it's something to keep in mind for the future.
Title: Re: LambdaHack
Post by: Man of Letters on August 06, 2014, 05:08:31 PM
This is always nice. While the current messages aren't always very clear, they are really helpful while developing a game. It's much easier to test things when possible problems are reported on a start up and not when the problem actually might occur.

I'm glad you think so, too. :)
I'm ready to publish LambdaHack 0.4.9.0. I may lazily test a couple more days
or publish at once if that's in any way helpful to you.

Quote
Static ones would be easier for end users.

Actually, I've just found this

http://stackoverflow.com/questions/8657908/deploying-yesod-to-heroku-cant-build-statically/8658468#8658468

and here is some more context

http://stackoverflow.com/questions/5953199/create-a-static-haskell-linux-executable

So it's not obvious if static libraries are better, though in our case they may be,
since we depend on lots of shared libraries:

Code: [Select]
~/r/LambdaHack$ ldd /tmp/LambdaHack
linux-vdso.so.1 =>  (0x00007fff055c0000)
libgtk-x11-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 (0x00007fc52f925000)
libgdk-x11-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgdk-x11-2.0.so.0 (0x00007fc52f673000)
libatk-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libatk-1.0.so.0 (0x00007fc52f450000)
libgdk_pixbuf-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x00007fc52f230000)
libpango-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007fc52efe7000)
libgobject-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007fc52ed97000)
libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007fc52eaa2000)
libgthread-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0 (0x00007fc52e8a0000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc52e697000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc52e480000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc52e27c000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fc52e00d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc52dd11000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc52daf4000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc52d8dd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc52d51d000)
libpangocairo-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007fc52d311000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007fc52cfdb000)
libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007fc52cdd5000)
libcairo.so.2 => /usr/lib/x86_64-linux-gnu/libcairo.so.2 (0x00007fc52cb17000)
libgio-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007fc52c7c7000)
libpangoft2-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007fc52c59d000)
libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007fc52c367000)
libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007fc52c155000)
libXrender.so.1 => /usr/lib/x86_64-linux-gnu/libXrender.so.1 (0x00007fc52bf4b000)
libXinerama.so.1 => /usr/lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007fc52bd48000)
libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007fc52bb37000)
libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007fc52b92f000)
libXcursor.so.1 => /usr/lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007fc52b725000)
libXcomposite.so.1 => /usr/lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007fc52b521000)
libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007fc52b31e000)
libgmodule-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007fc52b119000)
libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007fc52af11000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fc52acd4000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc52ff80000)
libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007fc52aa37000)
libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007fc52a819000)
libpixman-1.so.0 => /usr/lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007fc52a581000)
libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007fc52a359000)
libxcb-shm.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007fc52a156000)
libxcb-render.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007fc529f4b000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fc529d2c000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fc529b10000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc5298e5000)
libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007fc5296e2000)
libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007fc5294db000)

What is obvious, however, is that if we build with shared libraries, we should do that
on my old system and test on yours, since new libs are supposed to be compatible
with old binaries, but not the other ways around.

Quote
In the linking phase, I got following errors:
Code: [Select]
Linking dist/build/SpacePrivateers/SpacePrivateers ...
/usr/bin/ld: cannot find -latk-1.0
/usr/bin/ld: cannot find -lgdk_pixbuf-2.0

I didn't manage to get that far regardless of the combination of options.
The errors, mentioning "relocation R_X86_64_32", suggest some code compiled
for 32 bits is involved, but this may be any other kind of wierd bug, as well.
I'm on GHC 7.8.3 and on 64 bits Ubuntu 12.04.4.

I haven't tested the --whole-archive option yet,
but I don't quite understand how it differs from static linking
(does it link statically only some libs? or bundles shared libs with the binary?)

http://stackoverflow.com/a/12564602

I suppose I will just publish shared libs binaries with 0.4.9.0 and ask you
to try if they work for you.
Title: Re: LambdaHack
Post by: tuturto on August 07, 2014, 10:04:34 AM
I'm glad you think so, too. :)
I'm ready to publish LambdaHack 0.4.9.0. I may lazily test a couple more days
or publish at once if that's in any way helpful to you.

No need to rush I guess. I probably try to finish and publish first version of the game using the current version of LambdaHack and update to the next one after that. I'm thinking of declaring the current version I have what I'm going to release (not that there's that much of new content there yet, but it's a start). Still need to edit all guides and stuff that still read what LambdaHack came with.

Actually, I've just found this

http://stackoverflow.com/questions/8657908/deploying-yesod-to-heroku-cant-build-statically/8658468#8658468

and here is some more context

http://stackoverflow.com/questions/5953199/create-a-static-haskell-linux-executable

Hm.. that's interesting. I think that it would still be worthwhile to try to make a statically linked binaries. If for nothing else, then for the sake of an exercise :) And as you pointed out, LambdaHack has quite big list of dependencies and having to list all of them for end users to install before playing is bit tedious.

What is obvious, however, is that if we build with shared libraries, we should do that
on my old system and test on yours, since new libs are supposed to be compatible
with old binaries, but not the other ways around.

Sure, I would love to help testing things. I'm running a 32-bit system, but it should be possible to make 32-bit binaries in 64-bit system as far as I understand.

Title: Re: LambdaHack
Post by: Man of Letters on August 07, 2014, 10:30:28 AM
Quote
I probably try to finish and publish first version of the game using the current version of LambdaHack and update to the next one after that. I'm thinking of declaring the current version I have what I'm going to release (not that there's that much of new content there yet, but it's a start).

Great. So far, I like a lot, e.g.,  your general setting and the playful
but plausible names of things. :)

Quote
Hm.. that's interesting. I think that it would still be worthwhile to try to make a statically linked binaries. If for nothing else, then for the sake of an exercise :) And as you pointed out, LambdaHack has quite big list of dependencies and having to list all of them for end users to install before playing is bit tedious.

Yep. Perhaps ideally we should include all but glibc, but I don't know if that's possible
and in what way (even bundling the shared libs in subdirectories may make sense, actually).
I wonder what non-Haskell HOWTOs say about that.

Quote
I'm running a 32-bit system, but it should be possible to make 32-bit binaries in 64-bit system as far as I understand.

Ah, that may explain why you didn't have the 32bit-related errors that I encountered.
I guess I can make 32bit binaries, but I probably need 32bit versions of the libs installed.
I will try that. Anyway, I certainly makes sense to release both 64bit and 32bit binaries.

Have fun and no rush, indeed. :)
Title: Re: LambdaHack
Post by: Man of Letters on August 09, 2014, 07:20:19 AM
Congratulations on the first release!

https://hackage.haskell.org/package/SpacePrivateers
Title: Re: LambdaHack
Post by: tuturto on August 09, 2014, 09:22:00 AM
Congratulations on the first release!

https://hackage.haskell.org/package/SpacePrivateers

Thanks, and thank you for providing 64-bit binaries. The release is a bit rough, just simple readme, changelog and binaries. Next one should be a bit more fleshed out hopefully.

But before that, there's plenty things to do, like upgrading to the new version of LambdaHack when it comes out and adding more content.
Title: Re: LambdaHack
Post by: tuturto on August 16, 2014, 10:19:25 AM
I upgraded to the latest version of LambdaHack (0.4.99.0) without much of a problem. Game compiles and runs now, but I haven't added any new content yet. One new idea I have is a sect of tech-priests, who slowly wander through the ship, following their leader.

New validation routines saved my back couple of times, when I had inconsistent definitions for caves, modes and players.
Title: Re: LambdaHack
Post by: Man of Letters on August 30, 2014, 11:12:52 AM
Edit: this post has the AutoLeader details wrong. See a post below for a correction.

Quote
I upgraded to the latest version of LambdaHack (0.4.99.0) without much of a problem.

I'm glad to hear that!

Quote
One new idea I have is a sect of tech-priests, who slowly wander through the ship, following their leader.

This should be doable as on this line

https://github.com/LambdaHack/LambdaHack/blob/v0.4.99.0/GameDefinition/Content/ModeKindPlayer.hs#L66

which is documented at

http://hackage.haskell.org/package/LambdaHack-0.4.99.0/docs/Game-LambdaHack-Content-ModeKind.html#t:LeaderMode

but I'd better explain anyway. :)

LeaderAI means the faction has a leader and it's controlled by AI, True means
the leader will spontaneously switch to an actor on another level from time to time
(so you'd probably want to set False there), and False means the leader will never spontaneously
change to another actor on the same level (but it may be forced to switch, e.g., if the old leader dies).
Normally it's good for a faction to switch leaders, because the new leaders tend to be closer
to enemies/loot/etc. But, for role-playing reasons, your tech-priests need

Code: [Select]
  fleaderMode = LeaderAI $ AutoLeader False False

and this also brings some variety compared to other factions.

You'd also need to set tactic, as on this line

https://github.com/LambdaHack/LambdaHack/blob/v0.4.99.0/GameDefinition/Content/ModeKind.hs#L165

which sets the AI tactics for the party to follow-the-leader. BTW, you can manually change the tactics
of your party with CTRL-T. This is also useful for testing (e.g., make frontendSafari), in that you can
take manual control of the tested AI party with ESC, change tactics and resume the AI with CTRL-A.

Do you still want your hero party to follow their leader automatically? With LH 0.4.99.0 it's easier to do
and probably much closer to your intent. To be precise, your other party members follow the leader's target,
and if not set, only then they follow the leader's position. See above how to set that.
Title: Re: LambdaHack
Post by: tuturto on August 31, 2014, 07:35:10 PM
Thanks for the clear explanation. Haddock is really nice, but nothing beats a well written example. However, I managed to get my game into state where it doesn't run properly anymore, but terminates with an error:
Code: [Select]
Contract failed and the following is to blame:
  ( "unexpected leader"
, ( UpdLeadFaction
      (FactionId (-2))
      (Just ( ActorId 10 , Nothing ))
      (Just ( ActorId 10 , Just (TPoint (LevelId (-1)) ( 60 , 5 )) ))
  , Just (ActorId 12)
  )
)
I can't spot why the changes done in this change set (http://"https://github.com/tuturto/space-privateers/commit/77b812249704001ef1c801494635e59952886051") would cause such behaviour. I adds a new player and faction, but there isn't really anything special there that would cause the faction not to have a leader.

When I get this sorted out, I'll try your suggestion making rest of the squad to follow the player. That would be quite nice change, I would think.
Title: Re: LambdaHack
Post by: Man of Letters on September 01, 2014, 01:06:31 AM
Quote
I can't spot why the changes done in this change set (https://github.com/tuturto/space-privateers/commit/77b812249704001ef1c801494635e59952886051) would cause such behaviour.

You are right, your commit is fine. Congratulations, you've discovered a bug in the engine. ;)

I've now fixed the bug in the dev version but, fortunately, it should only mildly affect you
even if you use the released version. I have wrongly advised you to use AutoLeader True True
for your players to maximize the number of leader changes done by AI (which are usually beneficial).
In fact, for technical reasons, the correct incantation is AutoLeader True False.
If you use it, the bug will not manifest. Unfortunatley, for playerTechCult you'd need
AutoLeader False True, but that one would trigger the bug. So, for now, your cult
will change it's leader from time to time, I'm afraid. Technical details are at the end of this post.

BTW, _meleeAndRanged, though a fine choice for, e.g.,  playerMerchant,
does not fit playerTechCult, because it means the non-leader cultists will never move,
only melee or reaction-fire. You can spot such content errors by defining a few debug modes
where playerHero is controlled by AI and, e.g., playerTechCult has a UI client so that you can observe
how it behaves. See, e.g., 'make frontendDefense'.

fcanEscape = True means if any cultist reaches the spaceship exit, they win the game.
That is fun, a race to the exit, but to have a chance, either move their starting point down,
or move the spaceship exit down (see Allure of the Stars, where exit is at the opposite end of the ship).

fneverEmpty = True is weird for a faction that spawns, because as soon as
there is no actor left, the faction is announced to be defeated, but then, some turns later
another actor may spawn. I have no clue what happens then (I hope not a crash).
I will have to check the code, but perhaps in the future we should just try to cross-verify
fneverEmpty and cactorFreq in CaveKind and reject such content.
Anyway, thank you for the unexpected use case. :)

You may want to use LeaderNull instead of LeaderAI for most (half?) of your factions,
because each leader keeps a single level active. That means that up to 5 AI factions
may be concurrently exploring the dungeon on 5 different levels. There'll be no loot left before
you heroes get anywhere. :) TPatrol would help, but it's not yet implemented and there's even
less sense in a faction actively patrolling a level where no other faction has any actors.
With as many factions as you have, spreading out and establishing patrol areas
may be easily done when other non-human factions with leaders visit a level,
so that the patrolling faction is ready to get activated when the heroes come.


Technical details
-------------------

My wrong advice came from too simplified documentation (or too complex semantics),
to the point that it fooled even myself, after a particularly refreshing vacation.
The expanded documentation is below. The point is that in the current setup,
AI leader level changes are done exclusively by the server (hence True
in AutoLeader True False) and extensive AI leader switching without level changes
is done only by the client (hence False).

In the future, this should be more symmetric, with both kinds of leader changes available
both on the server and on the client. The server version would be more random, used as a mild drawback,
and the client version would be meticulous --- in case of leader level change, it would
maximize the chance of spawning a new party member, if the player that can spawn
on any levels (as specified per-level in CaveKind).

Code: [Select]
data AutoLeader = AutoLeader
  { autoDungeon :: !Bool
      -- ^ leader switching between levels is automatically done by the server
      --   and client is not permitted to change leaders
      --   (the frequency of leader level switching done by the server
      --   is controlled by @RuleKind.rleadLevelClips@);
      --   if the flag is @False@, server still does a subset
      --   of the automatic switching, e.g., when the old leader dies
      --   and no other actor of the faction resides on his level,
      --   but the client (particularly UI) is expected to do changes as well
  , autoLevel   :: !Bool
      -- ^ leader switching within a level is automatically done by the server
      --   and client is not permitted to change leaders
      --   (server is guaranteed to switch leader within a level very rarely,
      --   e.g., when the old leader dies);
      --   if the flag is @False@, server still does a subset
      --   of the automatic switching, but the client is permitted to do more
  }
Title: Re: LambdaHack
Post by: CaptainKraft on September 01, 2014, 06:45:26 PM
Curse you all for making me want to do some more Haskell programming!
Title: Re: LambdaHack
Post by: tuturto on September 01, 2014, 07:05:12 PM
Thanks, I got it working now :) I made a note on the source to update techCult after the next release is made. I also adjusted the skills of the factions a bit. Mostly I'm still trying to get a feel of the engine and trying out different things. Eventually tech cult will be moved to a special level made just for them. At that time I'll switch to LeaderNull for them I suppose, so they'll start wandering around the level only after player enters the special level.

BTW, I switched the default tactic for player faction to TFollow and also tried the CTRL+T to check various tactics available. I like sending team to explore and after they locate enemy, pull everyone together and tackle the enemy together. This is now much more fun to play than having to move each team member separately.

Curse you all for making me want to do some more Haskell programming!

Come to the non-strict side, our monads are filled with pure deliciousness :) But seriously, have you had a look at LambdaHack? I don't know much Haskell and I'm having trouble making even simplest things, but I'm having blast with it already. I'm currently trying to learn enough, so that I could help tackling the simplest tasks for it.
Title: Re: LambdaHack
Post by: Man of Letters on September 01, 2014, 07:40:58 PM
Quote
Mostly I'm still trying to get a feel of the engine and trying out different things.

Sure, have fun do bold things. :)

Quote
Eventually tech cult will be moved to a special level made just for them.

Actually, you can do that already. Start them at that level. Don't give them the AbTrigger skill (so that can't use stairs so they won't escape the level). In Content.CaveKind tweak the level, e.g., forbid other monsters spawning there and in cavesCampaign assign the cave to the level number. I fully expect you to trigger a bug or two, but that's just my hidden bonus for all this free comradely support. ;)

The LeaderNull idea is also neat, for this faction or for another. I haven't thought about that. In this way you race to get the items on the level before the enemy gets them. You only need to make sure the faction doesn't spawn on any other level (or on no level at all).

Quote
BTW, I switched the default tactic for player faction to TFollow and also tried the CTRL+T to check various tactics available. I like sending team to explore and after they locate enemy, pull everyone together and tackle the enemy together. This is now much more fun to play than having to move each team member separately.

Oh, I'm glad. I'm a perfectionist, so I detest my heroes making non-optimal moves and getting into each other's way. But I guess many people find it fun and strongly prefer faster play, just as you do. So, Space Privateers may become a hit much easier than Allure of the Stars, at least unless I add mouse selection and other tweaks to make manual moving of groups of heroes easier. Or perhaps you'll specialize in large battles and general mayhem and I'll have to focus Allure of the Stars on stealth, where every single move really matters.

Curse you all for making me want to do some more Haskell programming!

Muahaha. Resistance is futile. Come over and share your secret plans.
Title: Re: LambdaHack
Post by: Man of Letters on September 01, 2014, 08:19:24 PM
Quote
The LeaderNull idea is also neat, for this faction or for another. I haven't thought about that. In this way you race to get the items on the level before the enemy gets them. You only need to make sure the faction doesn't spawn on any other level (or on no level at all).

I got carried away. This won't work if other AI factions can use stairs and visit the special level --- that would trigger spawning or movement and exploration of the faction that inhabits the special level before heroes get there.

This gives me an idea to do just that in Allure --- have only animals and robots until certain level and don't introduce aliens with any pre-spawned actor. If I tweak animals and robots to avoid exploring other levels, I can surprise the player by a sudden onset of aliens once he wakes them up (that is, makes them start spawning, by visiting a level where they spawn) and then they start exploring the whole dungeon and attacking en masse.

Edit: typos and clarifications.
Title: Re: LambdaHack
Post by: Man of Letters on September 01, 2014, 10:57:40 PM
Actually, I just checked that the only factions in Allure of the Stars that have leaders are heroes and aliens. So I don't even need to modify animals and robots in any way to make sure that aliens don't start spawning until heroes get to the first alien-spawning level.

BTW,  tuturto, could you give the i386 binary a try? See http://forums.roguetemple.com/index.php?topic=3633.msg39382#msg39382. I'm getting closer and closer to Windows binaries, but I've got tired with these hacks recently (plus I try to document this on the Haskell wiki and open tickets as I go, which takes time).
Title: Re: LambdaHack
Post by: tuturto on September 02, 2014, 08:27:51 AM
Quote from: Mikon
Oh, I'm glad. I'm a perfectionist, so I detest my heroes making non-optimal moves and getting into each other's way. But I guess many people find it fun and strongly prefer faster play, just as you do. So, Space Privateers may become a hit much easier than Allure of the Stars, at least unless I add mouse selection and other tweaks to make manual moving of groups of heroes easier. Or perhaps you'll specialize in large battles and general mayhem and I'll have to focus Allure of the Stars on stealth, where every single move really matters.

True, with space privateers it's not that important that every move they make is perfect. They probably have had couple grogs before boarding the city vessel anyway ;) Which reminds me, that I should look into adding grog tankards into the game somehow. Maybe boost calmness and damage in melee, but decrease accuracy for a while.

Quote from: Mikon
This gives me an idea to do just that in Allure --- have only animals and robots until certain level and don't introduce aliens with any pre-spawned actor. If I tweak animals and robots to avoid exploring other levels, I can surprise the player by a sudden onset of aliens once he wakes them up (that is, makes them start spawning, by visiting a level where they spawn) and then they start exploring the whole dungeon and attacking en masse.

Actually, I just checked that the only factions in Allure of the Stars that have leaders are heroes and aliens. So I don't even need to modify animals and robots in any way to make sure that aliens don't start spawning until heroes get to the first alien-spawning level.

That sounds like a cool idea.

Quote from: Mikon
BTW,  tuturto, could you give the i386 binary a try? See http://forums.roguetemple.com/index.php?topic=3633.msg39382#msg39382. I'm getting closer and closer to Windows binaries, but I've got tired with these hacks recently (plus I try to document this on the Haskell wiki and open tickets as I go, which takes time).

I will do that in the evening and let you know how it turned out.
Title: Re: LambdaHack
Post by: CaptainKraft on September 02, 2014, 03:58:19 PM
It's very tempting to fire up some old Haskell code that I worked on. I never did get into any game programming with the language but I did enjoy learning about it and functional programming in general. Unfortunately I have to focus on class and my other game projects at the moment, but I will definitely be lurking around here to see what everyone can do with the language.

This framework looks like a great start for people getting into Haskell. Keep it up doods!
Title: Re: LambdaHack
Post by: Man of Letters on September 03, 2014, 08:19:47 AM
CaptainKraft, good luck with you other projects, but don't resist the Call of Haskell for too long. ;)

tuturto, thank you very much for checking out the i386 binaries.

Quote
They probably have had couple grogs before boarding the city vessel anyway ;) Which reminds me, that I should look into adding grog tankards into the game somehow.

What an oversight! ;) That can easily lead to mutiny and we don't yet have code for that (well, unless leader change is the code).

Quote
Maybe boost calmness and damage in melee, but decrease accuracy for a while.

Sounds resasonable, but unfortunately we don't yet have timed effects. This will be the main focus of post-v0.5 work,
probably involving FRP (functional reactive programming), because I want to (over)do this properly.
The best you can do for now is probably RefillCalm, Impress, a small PushActor, perhaps Paralyze/DropBestWeapon in you are nasty.

BTW, I've implemented and pushed the waking-up of aliens in Allure of the Stars. Thanks for the idea!

I've had a closer look at skills and I see that my advice to remove AbTrigger from fskillsOther of your playerTechCult was wrong.
The faction has a leader and fskillsOther only affects non-leaders, so it doesn't solve the problem. So, instead, you need to add

Code: [Select]
               AddSkills $ EM.singleton AbTrigger (-1)

To each member of this faction (in ItemKindActor). This will affect the leader as well.
Title: Re: LambdaHack
Post by: tuturto on September 04, 2014, 06:59:51 PM
Crisis averted, grog has been added:
Code: [Select]
grog = ItemKind
  { isymbol  = '!'
  , iname    = "grog tankard"
  , ifreq    = [("useful", 100)]
  , iflavour = zipPlain [Brown]
  , icount   = 1
  , irarity  = [(1, 3), (10, 1)]
  , iverbHit = "splash"
  , iweight  = 50
  , iaspects = []
  , ieffects = [ RefillCalm 30, Paralyze (3 + d 5)]
  , ifeature = [ toVelocity 25
               , Applicable, Identified ]
  , idesc    = "A tankard full of disgusting looking liquid, probably containing at least one or more of the following: kerosene,
                propylene glycol, sulphuric acid, rum, acetone, scumm, axle grease and battery acid."
  , ikit     = []
  }
Originally it was also doing d2 points of damage (because, frankly, it's disgusting), but I decided not to have that in the end.

I've had a closer look at skills and I see that my advice to remove AbTrigger from fskillsOther of your playerTechCult was wrong.
The faction has a leader and fskillsOther only affects non-leaders, so it doesn't solve the problem. So, instead, you need to add

Code: [Select]
               AddSkills $ EM.singleton AbTrigger (-1)

To each member of this faction (in ItemKindActor). This will affect the leader as well.

I should have been able to spot that too, but I didn't think of it enough. I'll do the change to respective actors.
Title: Re: LambdaHack
Post by: Man of Letters on September 10, 2014, 10:06:40 AM
tuturto, a nice video!

http://youtu.be/nv_iuqdhwDw

I've commented on it.

On another front, the Windows binaries I hacked via Wine seem to work. Seriously!
So, when you want to make a new release, let me know, I release
a new version of LH, you rebase and then I can easily generate
the Windows binaries for you.
Title: Re: LambdaHack
Post by: tuturto on September 10, 2014, 06:48:55 PM
Cool! What I read about cross-compiling Haskell, it didn't look particularly easy. Great that you got it working. I probably don't have enough new content yet to warrant a new release, but I'll keep that in mind. I would love to be able to show the game to my co-workers at work.
Title: Re: LambdaHack
Post by: Bear on September 10, 2014, 11:40:25 PM
Crisis averted, grog has been added:


After playing too much Dwarf Fortress, it is clear that "Sober" needs to be a status effect for dwarfs, and possibly pirates, conferring some minor disadvantages.  There might even be an intermediate state, "not drunk enough" then a fairly broad "normal" range where they are at full capabilities, with "too drunk" and "much too drunk" on the other side.
Title: Re: LambdaHack
Post by: Man of Letters on September 10, 2014, 11:53:10 PM
Quote
"Sober" needs to be a status effect for dwarfs, and possibly pirates, conferring some minor disadvantages.  There might even be an intermediate state, "not drunk enough" then a fairly broad "normal" range where they are at full capabilities, with "too drunk" and "much too drunk" on the other side.

That makes perfect sense. Engine-wise, we'd either need to wait for timed events and effects to let game developers add that counter from scratch, or we can use the already existing Calm counter, with some extra flavour messages to drive the point home. In the latter case, we'd turn off Calm regeneration for pirates and they'd depend on grog for that. Some balancing would be needed to make the lack of Calm not as crippling as it is now, perhaps again only for pirates or only in Space Privateers.

Waiting for a github ticket...
Title: Re: LambdaHack
Post by: Bear on September 11, 2014, 02:12:57 AM
Hmm.  Perhaps sober means calm regeneration is only at 1/3 normal.  Then you could have a crew of 'sober' privateers able to hold things together, with some friction, or even achieve full calmness, under normal circumstances, but they'd fall apart in the presence of anything that takes their calm away too fast.
Title: Re: LambdaHack
Post by: tuturto on September 11, 2014, 07:11:38 AM
Hey, how did I miss that. Grog has slight boost for calm already, but somewhat more complete model would be neat.

Currently calm affects if character can access to shared cache or use potions. Mikon, was there anything else that it affects?

I think I would wait for timed effects and have a privateers who is somewhat drunk to have advantage in combat. Could even add more alcoholic beverages with slightly varying effects and alcohol content.
Title: Re: LambdaHack
Post by: Man of Letters on September 11, 2014, 07:44:22 AM
Quote
I think I would wait for timed effects and have a privateers who is somewhat drunk to have advantage in combat. Could even add more alcoholic beverages with slightly varying effects and alcohol content.

That one slowly turns into a PEGI (ESRB) 21+ game. ;)

Quote
Currently calm affects if character can access to shared cache or use potions. Mikon, was there anything else that it affects?

Indeed, Calm below 2/3 of max inhibits any item manipulation involving the shared stash.
Also, summoning depends on and uses up Calm. Current Calm also bounds the sight radius.
And a nasty effect: at Calm 0, when an actor is impressed by enemies, he defects.

In the future there may be one or two more effects, but I think especially the last
one is grave enough, though not trivial to figure out in casual games. Perhaps I should
mention Calm in the message about the actor defecting. Anyway, it only happens in games
that have enough items (or organs) that impress enemies (or oneself).
Title: Re: LambdaHack
Post by: tuturto on September 11, 2014, 06:56:02 PM
Indeed, Calm below 2/3 of max inhibits any item manipulation involving the shared stash.
Also, summoning depends on and uses up Calm. Current Calm also bounds the sight radius.
And a nasty effect: at Calm 0, when an actor is impressed by enemies, he defects.

That last one is quite grave and good motivator keeping ones calm above 0. I wasn't aware of that or the sight radius cap. Thrown potions that lower calm just got really dangerous.
Title: Re: LambdaHack
Post by: tuturto on December 15, 2014, 07:47:42 AM
A new version of LambdaHack has been released and I upgraded Space Privateers to use it. Getting the program to type check was pretty fast and straight forward, but I seem to be having a problem in my campaign settings. After starting the game, I get the error:

Quote
Internal failure occurred and the following is to blame:
  ("no unique group",(starting,fromList [(campaign,[(1,(Id 0,ModeKind {msymbol = 'a', mname = "campaign", mfreq = [(campaign,1)], mroster = Roster {rosterList = [Player {fname = "Space Privateers", fgroup = hero, fskillsOther = fromList [(move,1),(melee,1),(displace,-100),(alter tile,1),(wait,1),(manage items,-100),(fling,1),(activate,-100),(trigger tile,1)], fcanEscape = True, fneverEmpty = True, fhasNumbers = True, fhasGender = True, ftactic = follow leader's target or position, fentryLevel = - (1) - (0), finitialActors = 3, fleaderMode = LeaderUI (AutoLeader {autoDungeon = False, autoLevel = False}), fhasUI = True},Player {fname = "Merchant Mariners", fgroup = merchant, fskillsOther = fromList [(move,-100),(melee,1),(displace,-100),(alter tile,-100),(wait,1),(manage items,-100),(fling,-100),(activate,-100),(trigger tile,-100)], fcanEscape = False, fneverEmpty = False, fhasNumbers = False, fhasGender = True, ftactic = find and patrol an area (TODO), fentryLevel = - (1) - (0), finitialActors = 3, fleaderMode = LeaderAI (AutoLeader {autoDungeon = True, autoLevel = False}), fhasUI = False},Player {fname = "Forces of Chaos", fgroup = chaos, fskillsOther = fromList [(move,-100),(melee,1),(displace,-100),(alter tile,-100),(wait,1),(manage items,-100),(fling,1),(activate,-100),(trigger tile,-100)], fcanEscape = False, fneverEmpty = False, fhasNumbers = False, fhasGender = True, ftactic = explore unknown, chase targets, fentryLevel = - (1) - (0), finitialActors = 3, fleaderMode = LeaderAI (AutoLeader {autoDungeon = True, autoLevel = False}), fhasUI = False},Player {fname = "Tech Cult", fgroup = tech, fskillsOther = fromList [(move,1),(melee,1),(displace,-100),(alter tile,1),(wait,1),(manage items,-100),(fling,1),(activate,-100),(trigger tile,-100)], fcanEscape = False, fneverEmpty = True, fhasNumbers = False, fhasGender = False, ftactic = follow leader's target or position, fentryLevel = - (2) - (0), finitialActors = 4, fleaderMode = LeaderAI (AutoLeader {autoDungeon = True, autoLevel = False}), fhasUI = False},Player {fname = "Horrors of Warp", fgroup = horror, fskillsOther = fromList [(move,1),(melee,1),(displace,1),(alter tile,1),(wait,1),(manage items,1),(fling,1),(activate,1),(trigger tile,1)], fcanEscape = False, fneverEmpty = False, fhasNumbers = False, fhasGender = False, ftactic = find and patrol an area (TODO), fentryLevel = - (3) - (0), finitialActors = 0, fleaderMode = LeaderNull, fhasUI = False},Player {fname = "Spawns of Warp", fgroup = spawn, fskillsOther = fromList [(move,1),(melee,1),(displace,-100),(alter tile,1),(wait,1),(manage items,-100),(fling,-100),(activate,-100),(trigger tile,1)], fcanEscape = False, fneverEmpty = False, fhasNumbers = False, fhasGender = False, ftactic = roam freely, chase targets, fentryLevel = - (2) - (0), finitialActors = 3, fleaderMode = LeaderAI (AutoLeader {autoDungeon = True, autoLevel = False}), fhasUI = False}], rosterEnemy = [("Space Privateers","Merchant Mariners"),("Space Privateers","Forces of Chaos"),("Space Privateers","Spawns of Warp"),("Merchant Mariners","Forces of Chaos"),("Merchant Mariners","Spawns of Warp"),("Tech Cult","Forces of Chaos"),("Tech Cult","Spawns of Warp")], rosterAlly = [("Forces of Chaos","Spawns of Warp"),("Merchant Mariners","Tech Cult")]}, mcaves = fromList [(-10,(caveRogue,Nothing)),(-9,(campaign random,Nothing)),(-8,(campaign random,Nothing)),(-7,(campaign random,Nothing)),(-6,(campaign random,Nothing)),(-5,(campaign random,Nothing)),(-4,(campaign random,Nothing)),(-3,(caveRogue,Nothing)),(-2,(temple,Nothing)),(-1,(caveRogue,Just True))], mdesc = "Get ready to assault the city vessel and plunder some loot!"}))])]))
SpacePrivateers: Control.Exception.Assert.Sugar.failure

I tried comparing my ModeKind.hs and ModeKindPlayer.hs to those of LambdaHack, but couldn't spot if I have a problem there somewhere.  Now, it would be cool if someone (Mikon for example ;) could give some pointers where to continue solving this problem.

I pretty excited about the possibility to have working storm hammers and privateer grog, so this update is something I want to get working soon.
Title: Re: LambdaHack
Post by: TheCreator on December 15, 2014, 07:57:17 AM
Does your code actually look like this? Creepy.
Title: Re: LambdaHack
Post by: tuturto on December 15, 2014, 08:02:42 AM
:D luckily not. That's just output of the data the program is validating and finding problems.

The actual code is more like:

Code: [Select]
-- | Basic players definitions.
module Content.ModeKindPlayer
  ( playerHero, playerMerchant, playerChaos, playerTechCult, playerHorror, playerSpawn
  ) where

import qualified Data.EnumMap.Strict as EM

import Game.LambdaHack.Common.Ability
import Game.LambdaHack.Common.Dice
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Content.ModeKind

playerHero, playerMerchant, playerChaos, playerHorror, playerTechCult, playerSpawn :: Player Dice

playerHero = Player
  { fname = "Space Privateers"
  , fgroup = "hero"
  , fskillsOther = allSkills
  , fcanEscape = True
  , fneverEmpty = True
  , fhasNumbers = True
  , fhasGender = True
  , ftactic = TFollow
  , fentryLevel = -1
  , finitialActors = 3
  , fleaderMode = LeaderUI $ AutoLeader False False
  , fhasUI = True
  }

playerMerchant = Player
  { fname = "Merchant Mariners"
  , fgroup = "merchant"
  , fskillsOther = meleeAdjacent
  , fcanEscape = False
  , fneverEmpty = False
  , fhasNumbers = False
  , fhasGender = True
  , ftactic = TPatrol
  , fentryLevel = -1
  , finitialActors = 3
  , fleaderMode = LeaderAI $ AutoLeader True False
  , fhasUI = False
  }

playerChaos = Player
  { fname = "Forces of Chaos"
  , fgroup = "chaos"
  , fskillsOther = _meleeAndRanged
  , fcanEscape = False
  , fneverEmpty = False
  , fhasNumbers = False
  , fhasGender = True
  , ftactic = TExplore
  , fentryLevel = -1
  , finitialActors = 3
  , fleaderMode = LeaderAI $ AutoLeader True False
  , fhasUI = False
  }

playerSpawn = Player
  { fname = "Spawns of Warp"
  , fgroup = "spawn"
  , fskillsOther = animalSkills
  , fcanEscape = False
  , fneverEmpty = False
  , fhasNumbers = False
  , fhasGender = False
  , ftactic = TRoam
  , fentryLevel = -2
  , finitialActors = 3
  , fleaderMode = LeaderAI $ AutoLeader True False
  , fhasUI = False
  }

playerTechCult = Player
  { fname = "Tech Cult"
  , fgroup = "tech"
  , fskillsOther = techSkills
  , fcanEscape = False
  , fneverEmpty = True
  , fhasNumbers = False
  , fhasGender = False
  , ftactic = TFollow
  , fentryLevel = -2
  , finitialActors = 4
  , fleaderMode = LeaderAI $ AutoLeader True False
  , fhasUI = False
  } -- TODO: change fleaderMode = LeaderAI $ AutoLeader False True

-- | A special player, for summoned actors that don't belong to any
-- of the main players of a given game. E.g., animals summoned during
-- a duel game between two hero players land in the horror faction.
-- In every game, either all factions for which summoning items exist
-- should be present or a horror player should be added to host them.
-- Actors that can be summoned should have "horror" in their @ifreq@ set.
playerHorror = Player
  { fname = "Horrors of Warp"
  , fgroup = "horror"
  , fskillsOther = unitSkills
  , fcanEscape = False
  , fneverEmpty = False
  , fhasNumbers = False
  , fhasGender = False
  , ftactic = TPatrol
  , fentryLevel = -3
  , finitialActors = 0
  , fleaderMode = LeaderNull
  , fhasUI = False
  }

minusHundred, meleeAdjacent, _meleeAndRanged, animalSkills, techSkills, allSkills :: Skills

-- To make sure weak items can't override move-only-leader, etc.
minusHundred = EM.fromList $ zip [minBound..maxBound] [-100, -100..]

meleeAdjacent = addSkills minusHundred
                $ EM.fromList $ zip [AbWait, AbMelee] [101, 101..]

-- Melee and reaction fire.
_meleeAndRanged = addSkills minusHundred
                  $ EM.fromList $ zip [AbWait, AbMelee, AbProject] [101, 101..]

animalSkills = addSkills minusHundred
               $ EM.fromList $ zip [AbMove, AbMelee, AbAlter, AbWait, AbTrigger] [101, 101..]

techSkills = addSkills minusHundred
             $ EM.fromList $ zip [AbMove, AbMelee, AbProject, AbAlter, AbWait] [101, 101..]

allSkills = addSkills minusHundred
            $ EM.fromList $ zip [AbMove, AbMelee, AbProject, AbAlter, AbWait, AbTrigger] [101, 101..]

I'm probably having some really simple problem that I'm too blind to spot.
Title: Re: LambdaHack
Post by: Man of Letters on December 15, 2014, 12:40:35 PM
tuturto, congratulations, you discovered the first bug in the new release of the engine. ;)

Took me quite some minutes to diagnose, because the code in question is obfuscated by my efforts to remain backward-compatible. Also, you didn't get the line number of the failure, because optimized libraries don't provide that (use 'cabal install LambdaHack -f-release' to get libs for development).

I'm afraid you have to put

Code: [Select]
   , mfreq    = [("campaign", 1), ("starting", 1)]
in GameDefinition/Content/ModeKind.hs. The good part is I'm now able to remove the backward-compatibility cruft, by assuming there's always a "starting" game mode defined in the content. :)

If you instead insert

Code: [Select]
screensaver = campaign
  { mname   = "campaign screensaver"
  , mfreq   = [ ("starting", 1)]
  , mroster = rosterCampaign
      { rosterList = (head (rosterList rosterCampaign))
                       {fleaderMode = LeaderAI $ AutoLeader False False }
                     : tail (rosterList rosterCampaign)
      }
  }

and add "screensaver" to the 2 lists where currently only "campaign" stands, the executable will by default run in screensaver mode (AI vs AI, you need to remove your save files to see it initially). See if you like it better.

Edit: actually, that you needed 'cabal install LambdaHack -f-release' was a bug. I've just fixed it. But in this case what would really help was a stack trace. For that you need `make install-debug` and then `make xcplay`.
Title: Re: LambdaHack
Post by: tuturto on December 15, 2014, 07:34:06 PM
Thanks, now it works. I played just briefly, so I didn't test everything, but everything so far works. Now I can start tinkering with the new features and see what kinds of things I can do with them. I'm going to add that screen saver mode back in too, should be helpful for testing. And it's fun to watch the game to play itself sometimes :)