Skip to content

maxlebedev/maleficer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maleficer

This is a classic roguelike with focus on tactical combat. The baseline combat of many rogulikes boils down to walking into enemies until they die, and I'm aiming to replace that with a more rich experiance. I also take inspiration from modern TTRPGs like Trespassor, especially in terms of mechanical clarity. (and a vehicle for teaching myself game dev, ecs pattern, etc) maleficer_mmenu_screenshot

Inspiration

- classic roguelikes
    * Pixel Dungeon
    * Shattered Pixed Dungeon
    * Dungeons of Dredmor
- Modern TTPGS like Trespassor
- Rift Wizard
- Tactics games, Survivorslikes
image

Dependancies

- libsdl2-dev
- export LIBGL_ALWAYS_SOFTWARE=1

Plot

The player is an ambitous and foolhardy wizard school dropout. They start with some default spells, but learn many more via exploration.

Mechanical Ideas

- teleportation/forced movement
- info gathering (bigger sight radius, heartbeat counter)
- terrain generation (create new hallways, wall pillars)
- grant status `Foo X` where x ticks down every turn (Bleed 3, Slow 2, etc)

Resource Ideas (partial alternatives to current cooldowns)

- Mostly cooldown based
- Stats: a stat for magic reserves, magnitude, duration, AOE size/range, etc
- Spell crafting
    * Collect spell portions ("glyphs" or "incantations")
    * These will be: damage, targeting criteria (aoe, range), debuffs
    * Maybe these modify base spells, maybe they are completely separate
    * Each of these would effect the cooldown
- Multiple mana bars
    * Each accumulates and gets spent in a slightly different way

Design Questions

- Why explore the level, (vs doing down asap)
    * Better Spell scrolls
- What is the progression system?
    * Between Games: Horizontal power scaling
        + New magical disciplines, with diff starting spells
    * In game
        + Better spells
        + Stat bumps

Map Plans

- cave levels
- laberynth levels
    * locked doors
- set-piece features
- BSP level
- Some Wave Function collapse?

Arch Concerns

- The Targeting phase and associated components are coupled to spell casting, if we have other things that target that'll need to change
    * Each effect component should have its own target, in case we have dmg+heal on one spell, for exampe
    * In the above case, there can be ambiguity about what the target phase actually sets
- Processors have verbose names, which include phases. Good hint to break them out to phase-based files. Some procs are shared tho
- I like context from breadcrumbs, but there is now a search issue with multiple apply functions, multiple Damage things, etc
- look into integer_scaling for context.present(console)
- Queries that return nothing can crash sometimes :(
- Should it be possible to ascend to a previous level (def not for now)
- Crosshair is a big exception to how movement works. might be worth its own function
- When I take a step, ranged enemies shoot me before step completes. feels correct for melee but unintuitive for range.
- MenuItem is used for actual menus, but not for inventory (not 1:1 with entities)
    * MenuSelection, however, IS reused to inventory
- Right now levels are limited to the board size. We could decouple those and have the board "scroll"
- should we always place the stairs as far back as we can?
- wet status from water tiles? are we that sort of game?
- We have two damage process steps, one for player damage, and one for everything else. This means enemies the player would kill don't attack back
- Bleed damage feels like it takes an extra turn. this is intentional. it only takes effect on the start of the turn after it is applied
- StepTrigger callbacks get their targets from the movement proc, in the OnStep case
- Because we allow already dead entities to resolve their queued damage, enemies get one final retaliation
- reusing Position components breaks things
- DeathTriggers with dmg need to have oneshot(Dmg) called after
- Warlock missles don't hit potions because they are not Blocking
- TargetInputEvent returns control to the player's Damage phase. otherwise enemies get a turn before player damage resolves
- instead of a melee decision tree, we do melee damage via bump func. 
    * this is undesirable
- Small Procs
    * A proposed refactor where we have much more procs, many with guards
    * each npc type, gets its own for example
    * this would hopefully replace Phases and callbacks
- The color scheme is.. color balanced for backing candle light
    - at least for NPCs
- Conditions live in a State cmp, in a single dict
    * we could have them all be children of a StatusEffect parent class 
    * and a bunch of separate cmps

TODO

Systems due for a pass

- "Effects" / Events
    * Effects and triggers might not want to be separate?
    * OnDeath/DeathTrigger OnStep/StepTriger redundancy.
        + The 'On's could be more ECS-compliant
        + Potentially unscheduled procs
- Bump is complex enough for its own system
    * not sure how it interacts with movement sys tho
- Spell resolution should def be its own (unscheduled) Proc
- Menu System. menuselection, vs how inventory does it
- I want to reimpl all of the status stuff as their own Components
    * They would be children of the Status cmp
    * and ecs.has would check for it
    * But ECS doesn't "do" subclasses. so I'd need a lookup thing
    * Do we modify the query func to work on superclasses? can we?
    * At minimum, get Condition our of typ
- Targeting. Decouple it from spellcasting

Core

- Save/Load
    * sqlite db for storing current lvl value, rng seed for lvls, etc
- the ecs.remove syntax is awkward
    * overwriting self.entities state in filter necessitates it for now
- callbacks are a violation of ECS. consider avoiding them somehow
    * the things that are now callbacks can be Small Procs, with a guard
    * for nav menu items, a NavButton cmponent with a *to* arg for phase
        + these having to coexist with current buttons might be too complex?
        + the char select buttons are both
    + there's probably a way to make the menu button handler via small_proc
- bresenham_ray should *really* be under test
- 2x2 enemies
    * game currently assumes positions are one cell, pieces have one pos
    * If I have 2x2, then I can make snakes too
- break up Arch Concerns into open questions and arch docs
- All effects on the targeting entity should get their targets filled in if they haven't already
    * But, only the non-static targets should get cleared, and we don't have a way to store that info
- effect application restrictions. (mutilate can't hit traps)
- an Ephemeral component for Crosshair, Area Effect type stuff
- Entity templates: cmp collections for easy entity creation
- The main callback that needs a ref to source is lob_bomb
    * It sure would be nice if it didn't need that
    * We could rewrite lob_bomb as a proc. LobberNPC or something
        + This also paves the way for every npc to have their own proc
- global tracking of targeted squares, with enemy ai to avoid them
- an effect:color mapping? "stun": Cyan, "force_move": Orange
- Do I want to split the "level phsae" into 3 parts?
    * up to player turn, npc, aftermath
- behavior.py can be divided into eval funcs, apply, and action

Game Mechanics/Balance

- spell mods (+1 range, +1 dmg pickups)
- cooldown alternatives like damage taken, steps walked (lotta tracking)
- spell burnout (ie how spammable a spell is)
    * using a spell accumulates one stack of burnout
    * burnout decreases by one every [max cooldown]+1 turns
    * when burnout reaches [max cooldown], increase [max cooldown] by 1
        + but do it in some temp way
    * [max cooldown] decreases again in like [max coldown]*2 turns
    * Alternat mechanic?, Burnout is a cap of off-cooldown uses.
        + If you use off cooldown B times, then you accumulate 1 burnout
        + and that takes B * CD to clear
- Some sort of Storm/Combo mechanic would be really cool
- Check for more places that benefit from ecs.Query.where
- mageblight: a curse that harms player when they don't progress the game
    * probably when they spend N turns without killing an enemy
    * escalates in damage
- prefabs for BDP map
- X/TAB to examine, target mode without casting spell
    * This gives us a good reason to decouple target from spell
    * Are we fine printing only one desc if the spell's aoe covers more?
- damage types. Not sure if elemental or what, but weaknesses, resistances
    * color code these things, so spells aren't just white on log
- it would be cool to use scrolls as materials for something
    * if you roll a bad spell, it shouldn't just be trash
- A map type that is actually the inside of a creature
    * The walls shift and can "swallow"
- Terrain tiles. Grass that blocks LOS, water that ...?
- Max HP as a resource (not for normal spells)
- Cryomancer with lengthier stuns
    * 3 turn stun, and a 1-speed icicle projectile
    * need to replace Spell.target_range with range func for icicle

Enemies

- Spawners
- "Commander" Enemies that effect their faction
- missile-launcher structure, checker pattern aoe
- one-turn-per-square moving projectiles
- goblins should actually try to be at dist 4 to player
    * when on cooldown BFS a position with dist 4, then move a step
- living flames move up to 2 squares to enemy
    * want an animation for getting there
    * if only moving 1 square can also attack
    * if its 2 squares away, player moves into, flame overreaches
    * might want to wait onthe NPC rework
- Weaken X. Deals -X damage
- Giant spider thing that leaps at you, with an AOE dmg on land
    * Same for charger enemies
- Portals, that are like traps with the on-step
    * but instead of dmg, position changes

UX

- use that M icon
- other menus probably want backgrounds.
    * side panels might too
- TargetRender.render and _apply_lighting need a DRY pass/refactor
- Decoupling board from screen size
    * I can't change tile size, and 8x8 is good for side panels
    * Given that I can't change tile size, I might not want to do this
- black fg plus grey/green bg could look rly cool
- Push 1 is an easy effect to miss, as the enemies move right back
    * Maybe all Push 1 comes with Stun 1

BUGS

- Found a wall I was able to walk through in the old caves.
    * Sometimes enemies turn into walls when they die
    * those walls can be walked through
    * I think this is bc enemies spawn *in* the wall with same pos
- Actual menuselection is on cmp.MenuSelection. not the GameMeta
- Living flame needs a rework. doesn't acutally move twice
    * We probably block this on NPC rework
- push_coords has no bounds checking.
    * Because we do a cell lookup, this isn't safe
- cursor mvmt has no bounds checking
- Push + dmg spells apply their push before dmg, causing the dmg to miss
    * Ideally, we would collect targets before applying any effects

About

A traditional roguelike with strong influence from modern ttrpg design

Resources

License

Stars

Watchers

Forks

Packages

No packages published