Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Disco Elysium Pre-Release Thread [GO TO NEW THREAD]

vmar

Savant
Joined
Oct 17, 2015
Messages
210
You're having a meltdown
 

Jinn

Arcane
Joined
Nov 8, 2007
Messages
4,930
The title is excellent. It's not their fault a bunch of people see Furries instead of Furies. The english language shall not be held captive by the foolishness of the modern day!
 

Kasparov

OH/NO
Developer
Joined
Jun 10, 2016
Messages
930
Location
ZA/UM
Seriously though it is a bad title, how committed are these guys to it?
Hey! Stop bitchin´ dawg and get in the game - read more about code, bro:


"Better Living Through C# Coding, Part 2: Magic Of Reflection"

ve.jpeg

Veljo Hagu
Systems Architect

(Part 1 can be found here.)

“Mirror, mirror on the wall, what’s the ugliest code of ’em all?”

The answer might very well be the annoying amount of technical code we need to implement in our components. Luckily, it annoyed me enough to start pondering about a better way. Specifically, about using attributes and reflection to hide all that ugliness inside a base class.

In the magical world of unicorns and rainbows, I want my Observer component to look pretty:

DemoInputObserver2.cs
usingUnityEngine;

publicclassDemoInputObserver2:BaseComponent{

[InputKey(KeyCode.Space)]
protectedvoidOnSpacebar(){
Debug.Log("Spacebar was pressed");
}

[InputKey(KeyCode.Escape, priority =10001)]
protectedvoidOnEscape(){
Debug.Log("Escape was pressed");
}

[InputAxis("Horizontal")]
protectedvoidOnHorizontal(float value){
Debug.Log("Horizontal axis = "+ value.ToString());
}
}
The idea is to use custom attributes to establish usage context: what type of input do we want to handle, and values for relevant parameters (KeyCode, name of the axis, handling priority, etc.). We rely on a common base class to discover those attributes and register thus marked methods with input manager.

Implementation-wise, starting with simple things, the custom attributes themselves are quite straight-forward:

InputAttribute.cs
usingUnityEngine;

publicabstractclassInputAttribute:System.Attribute{

protectedint? _priority;

publicbool hasPriority {get{return _priority!=null;}}

publicint priority {
get{return _priority!=null?(int)_priority :0;}
set{ _priority = value;}
}

publicInputAttribute(){ _priority =null;}
}

/// <summary>Attaching this attribute to a method marks it as HotKeyEventData handler. That method should have a single HotKeyEventData type argument.</summary>
[System.AttributeUsage(System.AttributeTargets.Method)]
publicclassInputEventDataAttribute:InputAttribute{

publicInputEventDataAttribute():base(){}
}

/// <summary>Attaching this attribute to a method marks it as Input.GetAxis value handler. That method should have a single float type argument.</summary>
[System.AttributeUsage(System.AttributeTargets.Method)]
publicclassInputAxisAttribute:InputAttribute{

publicstring axis {get;set;}

publicboolIsAxis(string a){return!string.IsNullOrEmpty(a)&&string.Equals(axis, a);}

publicInputAxisAttribute(string axis):base(){this.axis = axis;}
}

/// <summary>Attaching this attribute to a method marks it as Input.GetButtonDown event handler. That method should have no arguments.</summary>
[System.AttributeUsage(System.AttributeTargets.Method)]
publicclassInputButtonAttribute:InputAttribute{

publicstring button {get;set;}

publicboolIsButton(string b){return!string.IsNullOrEmpty(b)&&string.Equals(button, b);}

publicInputButtonAttribute(string button):base(){this.button = button;}
}

/// <summary>Attaching this attribute to a method marks it as Input.GetKeyDown event handler. That method should have no arguments.</summary>
[System.AttributeUsage(System.AttributeTargets.Method)]
publicclassInputKeyAttribute:InputAttribute{

publicvirtualKeyCode keyCode {get;set;}

publicInputKeyAttribute(KeyCode keyCode):base(){this.keyCode = keyCode;}
}
Reflection also turns out to be easy to use. The base class that you inherit from can be as simple as:
usingUnityEngine;
usingSystem.Reflection;

publicclassBaseComponent:MonoBehaviour{

protectedvoidInitManagerAgents(){
MemberInfo[] members =this.GetType().GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
foreach(MemberInfo m in members){
System.Attribute[] attribs =System.Attribute.GetCustomAttributes(m,false);
foreach(System.Attribute a in attribs){
//if (a is UpdateAttribute) UpdateManager.Register(this, m, a as UpdateAttribute);
if((a isInputAttribute)&&(m isMethodInfo))InputManager.Register(this, m asMethodInfo, a asInputAttribute);
}
}
//if (this is InputManager.IKeyHandler) InputManager.Register(this as InputManager.IKeyHandler);
}

protectedvirtualvoidAwake(){
InitManagerAgents();
}
}
Virtually all of the complexity is left for InputManager to handle. All we’re providing is reference to self, MethodInfo (which has Invoke method for callback), and InputAttribute providing context.

Lo and behold, the magic module.

InputManager.cs
[Persistent,SelfSpawning(name="InputManager")]
publicclassInputManager:SingletonComponent<InputManager>{

publicinterfaceIKeyHandler{
KeyCode inputKey {get;}
voidOnInputKey();
}

publicinterfaceIPriority{
int inputPriority {get;}
}

publicclassEventData{
publicstring axis =null;
publicstring button =null;
publicKeyCode keyCode =KeyCode.None;
publicbool used =false;
publicfloat value =0f;

publicEventData(KeyCode keyCode){this.keyCode = keyCode;}
publicEventData(string axis,float value){this.axis = axis;this.value = value;}
publicEventData(string button){this.button = button;}
}

/// <summary>Register an axis as one of interest.</summary>
publicstaticvoidObserveAxis(string axis){
if(!string.IsNullOrEmpty(axis)&&Singleton)Singleton.observedAxes.Add(axis);
}

/// <summary>Register a button as one of interest.</summary>
publicstaticvoidObserveButton(string button){
if(!string.IsNullOrEmpty(button)&&Singleton)Singleton.observedButtons.Add(button);
}

/// <summary>Register a keycode as one of interest.</summary>
publicstaticvoidObserveKeyCode(KeyCode keyCode){
if(keyCode!=KeyCode.None&&Singleton)Singleton.observedKeycodes.Add(keyCode);
}

/// <summary>Register a handler method for hotkey event with one above currently highest priority.</summary>
/// <param name="Action">Handler method that is called when hotkey event triggers. That method has one HotKeyEventData parameter.</param>
publicstaticvoidRegister(System.Action<EventData>Action){
if(Action!=null&&Singleton!=null)Singleton.GetBlock(Singleton.highestPriority +1).Event+=Action;
}

/// <summary>Register a handler method for hotkey event with the specified priority.</summary>
/// <param name="Action">Handler method that is called when hotkey event triggers. That method has one HotKeyEventData parameter.</param>
/// <param name="priority">Callbacks are made in order of priority (from the highest to the lowest).</param>
publicstaticvoidRegister(System.Action<EventData>Action,int priority){
if(Action!=null&&Singleton!=null)Singleton.GetBlock(priority).Event+=Action;
}

publicstaticvoidRegister(IKeyHandler handler){
if(handler!=null&&Singleton!=null)Singleton.AddAgent(newKeyHandlerAgent(handler));
}

publicstaticvoidRegister(Behaviour parent,System.Reflection.MethodInfo methodInfo,InputAttribute attribute){
if(methodInfo==null||!parent ||!Singleton)return;
if(attribute isInputEventDataAttribute){
Singleton.AddAgent(newEventDataAgent(parent, methodInfo, attribute asInputEventDataAttribute));
}elseif(attribute isInputAxisAttribute){
Singleton.AddAgent(newAxisAgent(parent, methodInfo, attribute asInputAxisAttribute));
}elseif(attribute isInputButtonAttribute){
Singleton.AddAgent(newButtonAgent(parent, methodInfo, attribute asInputButtonAttribute));
}elseif(attribute isInputKeyAttribute){
Singleton.AddAgent(newKeyCodeAgent(parent, methodInfo, attribute asInputKeyAttribute));
}
}

/// <summary>Unregister a callback method from all timer events.</summary>
publicstaticvoidUnregister(System.Action<EventData>Action){
if(Action!=null&&Singleton!=null)foreach(EventBlock b inSingleton.eventBlocks) b.Event-=Action;
}

protectedabstractclassEventHandlerAgent:Agent{

protectedSystem.Action<EventData>Action;

publicEventHandlerAgent(Behaviour parent):base(parent){}

publicoverridevoidDispose(){
if(Action!=null)Unregister(Action);
Action=null;
base.Dispose();
}
}

protectedclassEventDataAgent:EventHandlerAgent{

publicEventDataAgent(Behaviour parent,System.Reflection.MethodInfo methodInfo,InputEventDataAttribute attribute):base(parent){
if(IsFinished)return;
Action=(x =>{if(!IsFinished&& parent.isActiveAndEnabled) methodInfo.Invoke(parent,newobject[]{ x });});
if(attribute!=null&& attribute.hasPriority)Register(Action, attribute.priority);
elseRegister(Action);
}
}

protectedclassAxisAgent:EventHandlerAgent{

publicAxisAgent(Behaviour parent,System.Reflection.MethodInfo methodInfo,InputAxisAttribute attribute):base(parent){
if(IsFinished)return;
Action=(x =>{
if(!IsFinished&&!x.used && attribute.IsAxis(x.axis)&& parent.isActiveAndEnabled){
object res = methodInfo.Invoke(parent,newobject[]{ x.value });
if(res isbool) x.used =(bool)res;
else x.used =true;
}
});
ObserveAxis(attribute.axis);
if(attribute.hasPriority)Register(Action, attribute.priority);
elseRegister(Action);
}
}

protectedclassButtonAgent:EventHandlerAgent{

publicButtonAgent(Behaviour parent,System.Reflection.MethodInfo methodInfo,InputButtonAttribute attribute):base(parent){
if(IsFinished)return;
Action=(x =>{
if(!IsFinished&&!x.used && attribute.IsButton(x.button)&& parent.isActiveAndEnabled){
object res = methodInfo.Invoke(parent,null);
if(res isbool) x.used =(bool)res;
else x.used =true;
}
});
ObserveButton(attribute.button);
if(attribute.hasPriority)Register(Action, attribute.priority);
elseRegister(Action);
}
}

protectedclassKeyCodeAgent:EventHandlerAgent{

publicKeyCodeAgent(Behaviour parent,System.Reflection.MethodInfo methodInfo,InputKeyAttribute attribute):base(parent){
if(IsFinished)return;
Action=(x =>{
if(!IsFinished&&!x.used && x.keyCode!=KeyCode.None&& x.keyCode==attribute.keyCode && parent.isActiveAndEnabled){
object res = methodInfo.Invoke(parent,null);
if(res isbool) x.used =(bool)res;
else x.used =true;
}
});
ObserveKeyCode(attribute.keyCode);
if(attribute.hasPriority)Register(Action, attribute.priority);
elseRegister(Action);
}
}

protectedclassKeyHandlerAgent:EventHandlerAgent{

publicKeyHandlerAgent(IKeyHandler handler):base(handler asBehaviour){
if(IsFinished)return;
Action=(x =>{
if(!IsFinished&&!x.used && x.keyCode!=KeyCode.None&& x.keyCode==handler.inputKey && parent.isActiveAndEnabled){
handler.OnInputKey();
x.used =true;
}
});
ObserveKeyCode(handler.inputKey);
if(parent isIPriority)Register(Action,(parent asIPriority).inputPriority);
elseRegister(Action);
}
}

protectedclassEventBlock:System.IComparable<EventBlock>{

publicint priority;
publiceventSystem.Action<EventData>Event;

publicEventBlock(int p){ priority = p;}

publicvoidAppendTo(refSystem.Action<EventData> deleg){if(Event!=null) deleg +=Event;}

// Order highest to lowest
publicintCompareTo(EventBlock other){return-priority.CompareTo(other.priority);}

publicvoidInvoke(EventData eventData){if(Event!=null)Event(eventData);}

publicboolIsEmpty{get{returnEvent==null;}}
}

protectedAgentCollection agents =null;
protectedList<EventBlock> eventBlocks =newList<EventBlock>();
protectedHashSet<string> observedAxes =newHashSet<string>();
protectedHashSet<string> observedButtons =newHashSet<string>();
protectedHashSet<KeyCode> observedKeycodes =newHashSet<KeyCode>();


protectedboolAddAgent(Agent item){
if(agents==null) agents =newAgentCollection();
return agents.Add(item);
}

protectedEventBlockGetBlock(int priority){
foreach(EventBlock b in eventBlocks)if(b.priority==priority)return b;
EventBlock newBlock =newEventBlock(priority);
eventBlocks.Add(newBlock);
eventBlocks.Sort();
return newBlock;
}

protectedint highestPriority {
get{
// eventBlocks is always sorted in reversed priority order (i.e., highest to lowest), so first non-empty block is the correct result
foreach(EventBlock b in eventBlocks)if(b.priority<10000&&!b.IsEmpty)return b.priority;
return0;
}
}

protectedvoidSendEvent(EventData data){
System.Action<EventData> callStack =null;
foreach(EventBlock block in eventBlocks) block.AppendTo(ref callStack);
if(callStack!=null) callStack(data);
}

protectedvoidUpdate(){
foreach(KeyCode k in observedKeycodes){
if(Input.GetKeyDown(k))SendEvent(newEventData(k));
}
foreach(string a in observedAxes){
SendEvent(newEventData(a,Input.GetAxis(a)));
}
foreach(string b in observedButtons){
if(Input.GetButtonDown(b))SendEvent(newEventData(b));
}
agents.Update(Time.deltaTime);
}

protectedoverridevoidOnDestroy(){if(agents!=null) agents.Clear();base.OnDestroy();}
}
As you can see, there’s a bit more going on here than I have revealed the code for. All that has to wait for Part 3, as time is up for today. Sorry!
 

Kasparov

OH/NO
Developer
Joined
Jun 10, 2016
Messages
930
Location
ZA/UM
I don't have a clue why are you posting dev diaries about coding and shit. 10 people in whole world read that stuff.
This whole endeavor is a niche thing. Were not a big studio - more like a cobbler or a taylor. These "shoes" will fit those ten people and hopefully they'll wear that pair to ribbons and then some.

Are you guys actual communist pigs btw.? :M
Naw. Not really. I mean, I've seen more communists in Copenhagen than in Tallinn. Pigs? Sure! We're men's men. Oink! Oink!
 

ArchAngel

Arcane
Joined
Mar 16, 2015
Messages
19,887
I don't have a clue why are you posting dev diaries about coding and shit. 10 people in whole world read that stuff.
This whole endeavor is a niche thing. Were not a big studio - more like a cobbler or a taylor. These "shoes" will fit those ten people and hopefully they'll wear that pair to ribbons and then some.

Are you guys actual communist pigs btw.? :M
Naw. Not really. I mean, I've seen more communists in Copenhagen than in Tallinn. Pigs? Sure! We're men's men. Oink! Oink!
And seems 6 of those 10 read this topic and didnt' agree with me.

Instead of this dev updates give us those about characters, world, systems, more details about your unique combat.. you know the stuff that will make people beyond those 10 become interested in the game.
 

Kasparov

OH/NO
Developer
Joined
Jun 10, 2016
Messages
930
Location
ZA/UM
I don't have a clue why are you posting dev diaries about coding and shit. 10 people in whole world read that stuff.
This whole endeavor is a niche thing. Were not a big studio - more like a cobbler or a taylor. These "shoes" will fit those ten people and hopefully they'll wear that pair to ribbons and then some.

Are you guys actual communist pigs btw.? :M
Naw. Not really. I mean, I've seen more communists in Copenhagen than in Tallinn. Pigs? Sure! We're men's men. Oink! Oink!
And seems 6 of those 10 read this topic and didnt' agree with me.

Instead of this dev updates give us those about characters, world, systems, more details about your unique combat.. you know the stuff that will make people beyond those 10 become interested in the game.

You are welcome to organize a donation pool to sponsor special requests :) As has been said before - these posts are written in our free time after developer hours at the studio. There are only 24 hours in a day-night cycle.

There is no traditional cRPG combat in No Truce! If you thumb back a few pages in this very thread or go to fortressoccident.com if you prefer a blog layout, you'll find several articles on the world of No Truce! and about game systems.

Meanwhile - stay tuned! There will be more posts on skills and other systems in the future.
 

Howdy

Guest
This game looks like my


It certainly appears avant garde, which in these times of low creative risk is what especially entices. May you sell many copies and copulate with many being's :salute:
 

Kasparov

OH/NO
Developer
Joined
Jun 10, 2016
Messages
930
Location
ZA/UM
"THE DESIGN ETHOS OF OUR ROLE PLAYING SYSTEM"

kinematroopika-150x150.jpg

Robert Kurvitz
Game Designer

I’ve spent most of my adult life tinkering on this system. (Most sounded better than all.) It used to be huge and unwieldy, meant to span several books. Originally we wanted to build a set of tabletop rulebooks inseparable from it’s setting. An end-all, include-all sourcebook / setting for tabletop role playing. Over the years we’ve cut it down to fit on a napkin.

For “No Truce With The Furies” we adapted those same pen and paper rules for an isometric RPG. I firmly believe it was the right choice.

The years have seen a lot of critique of our own system and even more learning from others. We’ve followed the debates around J. Sawyer’s design for Pillars of Eternity, rated editions of D&D and even played Temple of Elemental Evil for it’s turn based engine. We’ve done our time, so to say. Today I want to share some of our main beliefs as designers of role playing systems. These are not the “pillars of our design”, just some reasoning behind our rule system. The list is meant to show where we’re coming from to fellow designers and RPG enthusiasts.


Concept art for our skill icons​

1) Only one
We make one system, one world – and that’s it. Everything goes into this one structure. All our ability for systematic thinking, all our knowledge of history. We iterate upon these rules until they are just right, the best numerical foundation for experiencing our world. And we make the world as complete and total as we can. And then we’re done. Wrap it up and send it into the future, New Testament style. We will never make a steampunk cyberpunk spyworld, Owls versus Foxes, Yarn Boy rule system.

2) Tyranny of cool
If a skill has a great name, if a talent is poetic, if a mechanic is haute tension – it’s in. We’ll make it work. Beautiful stuff does not get taken out because “someone somewhere” didn’t understand what it does. If it’s clunky or extraneous we iterate and redesign until it works. We will always have talent names longer than “Small Black Flowers That Grow In The Sky” and “The Intense Humming of Evil” combined.

3) Unsymmetrical is symmetrical
It’s good to have almost useless things and seemingly overpowered things. A good composition is not all equal parts. A good composition is equal experiences. There is great symmetrical tension and effect in a seemingly useless abilities that you try to use for the sake of cool. Pull off Spook, Shocking Grasp and Spell Thrust in Baldur’s Gate and you’re a wizard. All builds should not be viable, but all builds should be interesting. Some skills only pop up one or two times — they will be all the more special for it. While other’s buzz around as often as possible. (Empathy always tells you what people are feeling but when Shivers comes in, it’s a special moment.)

4) Fit on a napkin or fit in the trash bin
After a while, we want you to be able to draw the entire system on a napkin from your head. That’s how elegant and self contained we want it to be. There are four stats and everything folds back into their value. We only use six sided dice. We prefer the Babylonian system of sixes to the Roman system of tens. (Six is a more comprehensible number, ten is too vague and philosophical and includes a zero). If we have a number in the rules – 4, 3 or 6 – we will reuse it as often as possible. All numbers fold back into themselves, everything is it’s own cap, never multiply, never produce long formulas.

5) Small numbers
Congratulations, you just got +1 of something. It’s a big deal. Six is the maximum. You don’t get 28 experience, you get ONE POINT to put into a skill. That one point gives you the aforementioned +1 bonus. You don’t suffer 76 damage, you lose TWO LIVES. The smaller a number, the less you have of it, the more dramatic it will feel. We large mammals have two to three offspring. We have one home. We have two eyes. Our numerical values are large and chunky, losing one is tragic and gaining one is a triumph. Our system reflects that.

6) Innovate like a fool
Innovate for innovation’s sake. This isn’t a medical procedure, it’s a rule system for a game. If we see a way to ditch experience then let’s do it. Sure, we could divide a point into 100 experience and it would let us balance the game better, but let’s not. Let’s not do levels either, carrying around points has been done less. And how about GAME OVER if you run out of money? Let’s do a clock too. A real time of day system will let us build great systems around it, imagine the great names we can give to talents for evening people! Above all – introduce hugely ambitious superstructures. A great failure is ten times better than a small success.


Gosh! Even more concept art for our skill icons​

+1 Tabletop is god
We believe in great D&D. Not in high fantasy or cyberpunk but in the potential of the underlying tabletop experience. If the Game Master has a great story and the players are competent writers too… tabletop wipes the floor with any other medium. (Literature and video games included.) The Zola, Gombrowicz and Bulgakov of our time are already playing D&D, possibly around one table. The trouble is – the experience cannot be recorded and relayed to others. Tabletop is written on water.

Therefore we believe in video game adaptations of the tabletop experience. Games have had great success adapting tactical combat oriented D&D into video games. (Baldur’s Gate 2, etc). We want to do the same for heavy duty story oriented D&D.


#Drizzt
 

agris

Arcane
Patron
Joined
Apr 16, 2004
Messages
6,764
3) Unsymmetrical is symmetrical
It’s good to have almost useless things and seemingly overpowered things. A good composition is not all equal parts. A good composition is equal experiences. There is great symmetrical tension and effect in a seemingly useless abilities that you try to use for the sake of cool. Pull off Spook, Shocking Grasp and Spell Thrust in Baldur’s Gate and you’re a wizard. All builds should not be viable, but all builds should be interesting. Some skills only pop up one or two times — they will be all the more special for it. While other’s buzz around as often as possible. (Empathy always tells you what people are feeling but when Shivers comes in, it’s a special moment.)

4) Fit on a napkin or fit in the trash bin
After a while, we want you to be able to draw the entire system on a napkin from your head. That’s how elegant and self contained we want it to be. There are four stats and everything folds back into their value. We only use six sided dice. We prefer the Babylonian system of sixes to the Roman system of tens. (Six is a more comprehensible number, ten is too vague and philosophical and includes a zero). If we have a number in the rules – 4, 3 or 6 – we will reuse it as often as possible. All numbers fold back into themselves, everything is it’s own cap, never multiply, never produce long formulas.

5) Small numbers
Congratulations, you just got +1 of something. It’s a big deal. Six is the maximum. You don’t get 28 experience, you get ONE POINT to put into a skill. That one point gives you the aforementioned +1 bonus. You don’t suffer 76 damage, you lose TWO LIVES. The smaller a number, the less you have of it, the more dramatic it will feel. We large mammals have two to three offspring. We have one home. We have two eyes. Our numerical values are large and chunky, losing one is tragic and gaining one is a triumph. Our system reflects that.

[...]

+1 Tabletop is god
We believe in great D&D. Not in high fantasy or cyberpunk but in the potential of the underlying tabletop experience. If the Game Master has a great story and the players are competent writers too… tabletop wipes the floor with any other medium. (Literature and video games included.) The Zola, Gombrowicz and Bulgakov of our time are already playing D&D, possibly around one table. The trouble is – the experience cannot be recorded and relayed to others. Tabletop is written on water.

Therefore we believe in video game adaptations of the tabletop experience. Games have had great success adapting tactical combat oriented D&D into video games. (Baldur’s Gate 2, etc). We want to do the same for heavy duty story oriented D&D.
#Drizzt
Yes. Yes yes yes. Especially #3 & 5. You are learning creatures. I appreciate this.


edit: could you post higher (2x) resolution versions of those images? I'd love to actually see the detail in them.
 

Blaine

Cis-Het Oppressor
Patron
Joined
Oct 6, 2012
Messages
1,874,662
Location
Roanoke, VA
Grab the Codex by the pussy
"THE DESIGN ETHOS OF OUR ROLE PLAYING SYSTEM"

kinematroopika-150x150.jpg

Robert Kurvitz
Game Designer

I’ve spent most of my adult life tinkering on this system. (Most sounded better than all.) It used to be huge and unwieldy, meant to span several books. Originally we wanted to build a set of tabletop rulebooks inseparable from it’s setting. An end-all, include-all sourcebook / setting for tabletop role playing. Over the years we’ve cut it down to fit on a napkin.

For “No Truce With The Furies” we adapted those same pen and paper rules for an isometric RPG. I firmly believe it was the right choice.

The years have seen a lot of critique of our own system and even more learning from others. We’ve followed the debates around J. Sawyer’s design for Pillars of Eternity, rated editions of D&D and even played Temple of Elemental Evil for it’s turn based engine. We’ve done our time, so to say. Today I want to share some of our main beliefs as designers of role playing systems. These are not the “pillars of our design”, just some reasoning behind our rule system. The list is meant to show where we’re coming from to fellow designers and RPG enthusiasts.

Concept art for our skill icons​

1) Only one
We make one system, one world – and that’s it. Everything goes into this one structure. All our ability for systematic thinking, all our knowledge of history. We iterate upon these rules until they are just right, the best numerical foundation for experiencing our world. And we make the world as complete and total as we can. And then we’re done. Wrap it up and send it into the future, New Testament style. We will never make a steampunk cyberpunk spyworld, Owls versus Foxes, Yarn Boy rule system.

2) Tyranny of cool
If a skill has a great name, if a talent is poetic, if a mechanic is haute tension – it’s in. We’ll make it work. Beautiful stuff does not get taken out because “someone somewhere” didn’t understand what it does. If it’s clunky or extraneous we iterate and redesign until it works. We will always have talent names longer than “Small Black Flowers That Grow In The Sky” and “The Intense Humming of Evil” combined.

3) Unsymmetrical is symmetrical
It’s good to have almost useless things and seemingly overpowered things. A good composition is not all equal parts. A good composition is equal experiences. There is great symmetrical tension and effect in a seemingly useless abilities that you try to use for the sake of cool. Pull off Spook, Shocking Grasp and Spell Thrust in Baldur’s Gate and you’re a wizard. All builds should not be viable, but all builds should be interesting. Some skills only pop up one or two times — they will be all the more special for it. While other’s buzz around as often as possible. (Empathy always tells you what people are feeling but when Shivers comes in, it’s a special moment.)

4) Fit on a napkin or fit in the trash bin
After a while, we want you to be able to draw the entire system on a napkin from your head. That’s how elegant and self contained we want it to be. There are four stats and everything folds back into their value. We only use six sided dice. We prefer the Babylonian system of sixes to the Roman system of tens. (Six is a more comprehensible number, ten is too vague and philosophical and includes a zero). If we have a number in the rules – 4, 3 or 6 – we will reuse it as often as possible. All numbers fold back into themselves, everything is it’s own cap, never multiply, never produce long formulas.

5) Small numbers
Congratulations, you just got +1 of something. It’s a big deal. Six is the maximum. You don’t get 28 experience, you get ONE POINT to put into a skill. That one point gives you the aforementioned +1 bonus. You don’t suffer 76 damage, you lose TWO LIVES. The smaller a number, the less you have of it, the more dramatic it will feel. We large mammals have two to three offspring. We have one home. We have two eyes. Our numerical values are large and chunky, losing one is tragic and gaining one is a triumph. Our system reflects that.

6) Innovate like a fool
Innovate for innovation’s sake. This isn’t a medical procedure, it’s a rule system for a game. If we see a way to ditch experience then let’s do it. Sure, we could divide a point into 100 experience and it would let us balance the game better, but let’s not. Let’s not do levels either, carrying around points has been done less. And how about GAME OVER if you run out of money? Let’s do a clock too. A real time of day system will let us build great systems around it, imagine the great names we can give to talents for evening people! Above all – introduce hugely ambitious superstructures. A great failure is ten times better than a small success.


Gosh! Even more concept art for our skill icons​

+1 Tabletop is god
We believe in great D&D. Not in high fantasy or cyberpunk but in the potential of the underlying tabletop experience. If the Game Master has a great story and the players are competent writers too… tabletop wipes the floor with any other medium. (Literature and video games included.) The Zola, Gombrowicz and Bulgakov of our time are already playing D&D, possibly around one table. The trouble is – the experience cannot be recorded and relayed to others. Tabletop is written on water.

Therefore we believe in video game adaptations of the tabletop experience. Games have had great success adapting tactical combat oriented D&D into video games. (Baldur’s Gate 2, etc). We want to do the same for heavy duty story oriented D&D.


#Drizzt

Might even qualify for
b73d971abf.png
, if these guidelines are followed properly.
 

Infinitron

I post news
Staff Member
Joined
Jan 28, 2011
Messages
97,236
Codex Year of the Donut Serpent in the Staglands Dead State Divinity: Original Sin Project: Eternity Torment: Tides of Numenera Wasteland 2 Shadorwun: Hong Kong Divinity: Original Sin 2 A Beautifully Desolate Campaign Pillars of Eternity 2: Deadfire Pathfinder: Kingmaker Pathfinder: Wrath I'm very into cock and ball torture I helped put crap in Monomyth
Grognardy stuff but it's going to be rather different in the context of a story RPG with no combat system.
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom