Generally if there's inlined HTML/CSS or repetitive code somewhere it's because either it was generated that way or alternatively because the HTML/CSS is unique to something being displayed. In either case, it doesn't cause any combinatorial explosions and it's not copy pasted.
Hm, I'm not sure if this is generated (I know about wizards for items):
interaction-resources
(you can use some html templating here):
Code:
Line 18: true;<span class="indent"></span><i class="fa fa-chevron-circle-down fa-fw red"></i>: you take longer to accomplish tasks that would be otherwise trivial if you were not as tired, you might find yourself unable to do certain things, learning becomes harder, at very low values you may fall asleep randomly in some safe place;
Line 21: true;<span class="indent"></span><i class="fa fa-chevron-circle-down fa-fw red"></i>: your Stamina depletes slowly over time, faster when you exert yourself;
Line 25: true;<span class="indent"></span><i class="fa fa-chevron-circle-down fa-fw red"></i>: social interactions might become more difficult, learning becomes harder;
Line 29: true;<span class="indent"></span><i class="fa fa-chevron-circle-down fa-fw red"></i>: daily tedium takes its toll on you consistently, unpleasant events can push you even harder;
Line 35: true;<span class="indent"></span><i class="fa fa-chevron-circle-down fa-fw red"></i>: as you spend money you have less of it;
But mostly examples below.
Unless you consider a machine generating code to be copy pasting it, in which case, yeah kinda, but not really.
If its not manually modified, then its kinda ok (but harder to read anyway).
I have no idea what you mean by making it declarative considering that no language used to write the game uses the declarative paradigm.
Its not about language (they're all the same), but about code itself. For example, you can write imperative code in haskell and declarative code in javascript. Currently significant part of engine already declarative (rules, state transition, graphs), but there also too much specific imperative code everywhere which makes it a bit harder to read. Just to be sure, I'm not trying to impose anything, just sharing feedback.
For example,
determine-height-difference.state
, it shows most things I've talked about:
- there is copy-paste + attributes thing:
- npc and pc attribute height is different thing, which means there will be multiple description templates for them
- npc can be {short, average, tall}, but pc only {short, tall} by some reasons
- there is no support for npc in heels
- everything is defined as imperative code with GOTO (GOTO is ok, especially in games)
- instead of this it is possible to define that in declarative approach:
Code:
short = 0, average = 1, tall = 2;
// Note, its not assign of value, but assign of expression, which is dynamically calculated on access of attribute
char.total_height = sum(char.height, char.heels?.height, char.hat?.height); // Or we can have attribute height in clothes itself and just sum all .height of all elements inside char.
// Matrix of height differences (char1.height.values * char2.height.values, where '*' is set product), more declarative since describes state, not how to get it
height_diff = (char1, char2)=>[
// short average tall
equal, taller, taller,
shorter, equal, taller,
shorter, shorter, equal,
];
// OR at least
height_diff = [shorter, equal, taller][clamp(char1.height-char2.height, -1, 1)]
// where clamp = (value, start, end)=>Math.max(start, Math.min(value, end));
- its very basic conpcept, but already takes 50+ lines, which can make code unmanageble when more content added.
- it is impossible to set character height by user, need to know rules on how-to it selected (because of lack multi-valued attributes), and it is inconsistent:
for example: build petite+athtletic will trigger rules for is-short and is-tall at same time, which means for both short and tall npcs height will be equal to pc.
(maybe it was game mechanic, "try to create build with desired height"?)
It's not my problem to ensure that people make characters that make sense (in terms of appearance) as much as it's my problem to ensure people have the tools to create the character they want (within reason). The choices you make are the attributes, I'm not sure what else you want me to do with it. Same with the "descriptive templates" thing. Hair and eyes have different descriptive templates. There's no possible cross over between them, because there's never a case where you'd describe hair in the same way you'd describe eyes.
Well, in this specific case (warm+cold, small+big, thin+thick example, and multiple color choices) feels like bug. Multiple color choices is ok, but then better to use all colors, not randomly select one of them.
Also, if I understand correctly, same problem can happen when random character generator is used (and you cannot blame user for wrong choices) and in case of generated npcs (if they are planned).
About attributes, currently there is binary attributes instead of multi-valued one, which means that there is no information about theirs relations:
Code:
char.eyes.warm: false | true
char.eyes.blue: false | true
char.eyes.green: false | true
char.eyes.red: false | true
// instead of
char.eyes.temperature: cold | warm
char.eyes.color: blue | green | red
I understand, that it is easier to create queries about binary attrbiutes (using set logic) and it is a bit more efficient, since you can use bitset for attribute storage.
But you can still have set-logic queries and multi-valued attributes at same time:
- there is 'world' graph (just array) for every object (not OOP, just generic game object/concept, such as character or clothes)
- every item in graph has structure like this:
[tag, ...data]
, which has variable length (you can store and process it pretty efficiently).
- tag is edge in graph (indice in array of everything), which describes internal structure of node (set of fields names and nodes)
small example:
Code:
graph = [
// attribute values
'red',
'green',
'blue',
'warm'
'cold',
// color possible values
[0, 1, 2],
// temperature possible values
[3,4],
// character metadata (set of [field_name, edge to set of possible values])
[['color', 5], ['temperature', 6]]
// character (color red+blue, temperature warm)
[tag: 7, [0, 2], [3]],
]
- edges list here (which looks like array []) is actually set, which means you can dynamically select implementation based on size and density for efficient storage (sorted array, bitset, range).
- graph is directed, which means you can construst inverted graph (not sure if its correct term) which has different direction of edges (A->B converts to B->A).
- In inverted graph all values will have edges to elements/objects in which they used and since edge list is a set, we can do set logic operations on it:
inverted_graph[0].edges & inverted_graph[3].edges // set of all elements which has attribute 'red' and 'warm'
If you found this interesting, I can think of less invasive design (but its not that complex and pretty easy to implement actually).
BTW, there is pretty strict rules about names (capitalized 2+ chars), age (18-35) and limited color choices, which looks a bit inconsistent with idea of "any character is possible".
Hair and eyes is probably bad example (however it still can be used in generic templaces like '
[quantity, quality, size, age, shape, color, proper_adjective, purpose] {noun}
'.
More correct example (also about copy+paste):
Code:
// fingernail-colour-complex
Line 14: pink;[?pink|pink|pink painted|pink coloured]
Line 16: red;[?red|red|red painted|red coloured]
Line 17: rose;[?rose|rose|rose painted|rose coloured]
// lip-colour-complex
Line 12: red;[?red|red|red painted|red coloured]
Line 14: pink;[?pink|pink|pink painted|pink coloured]
Line 15: rose;[?rose|rose|rose painted|rose coloured]