This post is hidden in my dashboard long-long time ago. Because a 8 or nine years ago - fare before AI ages. I start to create a small RPG, based on older graphics, the time passed by and project start as react but later turn to nextjs/TS. Honestly now I don't using neither. But this is a bit of time travel how chaotic is my mindset that ages.
repo: (https://github.com/Pengeszikra/rogmor)
live: (https://rogmor.vercel.app/)
Now I vibecode even a much smaller RPG with gemini CLI: (https://dev.to/pengeszikra/the-royal-gazette-a-single-line-noble-intrigue-20nn)
Long-long time ago I decided to create some cool MMORPG program ... but I failed! Meanwhile I do lot of different jobs from seller (in RPG shop), graphic designer to front end developer. In a last few years my focus on react and functional programming, so now I can start write another (easy) MMORPG game.
Maybe after famous TODO application, the MMORPG is the next indie development goal, especial when we would you like to be a full stack developer.
I have to admit that I have been writing this post for more than a year. So you follow how improving my workflow by the time
Graphics form the past
My plan was don't spend too much time with graphic and RPG element. I grab out one of my old graphic set, and convert to sprite sheet. Because with react framework basic output is HTML, instead concentrate on program architect.
Roll Play Game Math
First of all a little function which one is essence of rpg math:
const leveling = (level, mod = 0.5, pow = 4, madd = 2) => Math.round(
mod * Math.pow(level, pow) + (madd * level)
);
For example, if we would like level cap set to 60, and best value on that level is near 80k, then after few minutes tweak get the next result, which means we can control our result by mod value settings:
Array(60).fill().map((_,lvl) => leveling(lvl + 1, .3426, 3, 100));
// = [100, 203, 309, 422, ..., 72645, 76263, 80002]
Technical stack 1st version:
- fre :: react like JSX based framework
- react-troll :: my state handling helper for react
- callbag :: really interesting functional stream programming js solution
- deno :: instead node.js / avoid node_modules hell.
- some noSQL database :: maybe mongoDB
Technical stack leap to NEXT
- typescript :: higher order languages for JS reason :: static typing.
- nextjs :: react like hybrid static & server rendering js framework
- openAI :: The latest technical stack is including some AI for workflow.
Architect decisions
MMORPG program is fare better case for make well strict architect decisions compared by ordinary TODO application. I try to list my decisions:
- front end design pattern
- communication between front end and back end
- skeleton of ui
- state handling on user side
- database
- server side design pattern
- RPG rules
- Single or Multiple hero game
Question is: How can I handle quite complex UI by minimal state, maybe:
json {root: '', modal: ''}
Then link and openModal solve this single page app UI main state.
Important Pieces of MMORPG
I choice multi hero managament system instead single one because this means don't need to too much details for items.
- Login
- Hire Hero
- Loot
- Resources
- Items
- Hero Leveling
- Combat
- PVE
- PVP
- Area
- Metagames
- Login Rewards
- Advertising
Complex state-reducer-actions flow by callbag
Probably RPG game game mechanic is quite complex so lets try it, it seems to work on early iteration, but I tell the truth it is so over engineered!
NextJS the road to fullstack
The new gamechenger framework is the NextJs which one is capable to made client and server side code with one language ... and one repo so this is what I waiting so long.
Reach the cloud
For multiuser application is deffinetly need some database. In old time I think about own VPN server with capable to run database and server side code. But NextJS as gamechanger framework allow to me whole code written in one repo. Just the database still as question.
I found the mongoddb cloud good place to reach my data from anywhere. So it is meet needs.
Encounter Saga
Decide between the callbag (functional js library) and redux-saga (declarative generator extension for react), so winner is SAGA. So basic turnbased encounter core code looks like this:
export function * encounterSaga (encounter:Encounter) {
while(true) {
const {mobList, situation} = encounter;
const activeMob:Mob = turnGoesTo(mobList, situation);
const {payload:act} = firstMob.isUser
? yield take(USER_ACT)
: yield call(npcActSaga, activeMob , encounter);
;
const outcome:OutcomeList = yield call(playTurnSaga, encounter, act);
yield putAction(PLAY_ACTION, act);
yield putAction(PLAY_OUTCOME, outcome);
if (outcome.includes(Outcome.ENDED)) yield cancel();
}
}
Slash the domain driven script languge
Each hero have own skillset, for simplify the coding this skills, I maded a little script language which looks like Tailwind but this result is very different:
after put together slas script with saga the combat controll logic looks like this:
labelled while help me to simplify the saga.
export function * combatZoneSaga() {
while (true) {
const {payload:encounterTeams} = yield take(ENCOUNTER_BEGIN);
const {hero}:MainState = yield select();
const pickProf = () => pickOne(Object.keys(skillForProf))
const combatSetupMobList = encounterTeams.map(([lvl, type, team, avatar]:[number, ProfessionKey, Team, number]) =>
makeMob(lvl, type, team, avatar)
);
yield putAction(SET_MOB_LIST, combatSetupMobList)
let mobList = combatSetupMobList;
_CombatIsOver_: while (true) {
const order = actionOrder(mobList);
while (order.length) {
const [actor]:OrderOfSeed = order.shift();
yield putAction(PLAY_FLOW, {who: actor.uid});
const skillList = getSkillObject(actor);
const {isAutoFight} = yield select();
const subList = yield call(userChoiceTheSkillSaga, skillList, actor, isAutoFight)
if (subList === null) break _CombatIsOver_;
_NextActor_: while (true) {
if (subList.length < 1) break _NextActor_;
const [, command] = yield race([
delay(BATTLE_SPEED),
take([HEART_BEAT, ENCOUNTER_OUTCOME]),
])
if (command?.type === ENCOUNTER_OUTCOME) break _CombatIsOver_;
const skill = subList.shift();
const [aiTargetting, skillResult] = getSkillResult(actor, skill, mobList);
yield putAction(PLAY_FLOW, aiTargetting);
yield putAction(PLAY_FLOW, skillResult);
mobList = yield call(skillReducer, mobList, skillResult);
yield putAction(SET_MOB_LIST, mobList);
const isTwoTeam = mobList
.filter(isCapableToAction)
.map(mob => mob.team)
.find((item, _, arr) => arr.indexOf(item) !== 0)
;
if(!isTwoTeam) {
yield putAction(FOCUS_ON, null);
break _CombatIsOver_;
}
}
}
}
yield call(calculateEncounterResultSaga, mobList);
}
}
Auto content generate by ChatGPT
Suddenly I meet the crazy AI ChatGPT so my first stepp is I implementing to the blog part.
I was begin implement chatGPT to my blog section. If I start some question with ::, then prompt send to AI api and get back the answer as sage told something.
Second thing which was implemented is openAI DALL-E-2 image generatior page as show below. Even this post cover image is also generated by the program, and extended image with DALL-E editor
ai-image end point
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (!req.query?.seek) return res.status(404).json({msg:"- - Seek something? - -"});
const key = process.env.GPT_3_KEY || '- - -';
const headers = new Headers({
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json',
});
fetch(
"https://api.openai.com/v1/images/generations",
{
method: 'POST',
headers,
body: JSON.stringify({
"prompt": req.query.seek,
"n": +req.query.n ?? 1,
"size": req.query.size || "256x256",
})
}
)
.then(r => r.json())
.then(msg => res.status(200).json(msg))
.catch(error => res.status(404).json(error))
}
Maybe I will create additional game UI element design with DALL-E help.
TODO list for finish post
- [+] Write lost part back to the post
- [-] rework api end points from GET to POST
- [-] authentication/login solution for rogmor.app
- [-] minimal gameplay progress
- [-] ask image or text answer from Sage





Top comments (0)