Question inspired by the accepted answer to another question: Wondering if there is a more efficient way to store level data in my game?
The answer, by @Evorlor, says:
You should have the data for your level in an external source, such as an XML, JSON, YAML, CSV, or even a .txt file. Then you write your logic to read from the file, and generate the level procedurally.
This will let you play all of the levels with the same code, and you can make changes to levels, or add new levels, without touching the code. This also lets designers who aren't familiar with programming to create fun levels.
This also opens the door for user-generated content. You can create a level editor that auto-generates this file. A level editor will also make it easier to make fun levels, since they can be visually designed, instead of by writing text into a doc.
I have great doubts about this line of reasoning.
Years ago I tried (and failed) to make my own Pokemon-like game. Inspired by The Battle for Wesnoth and its WML (Wesnoth Markup Language) config files that could encode entire scenarios, units and abilities I thought I'd do the same. I'd encode monsters, abilities and types in configuration files; then my game would read these config files on startup. There'd be next to nothing hardcoded.
This proved to be a terrible idea. Especially abilities proved to be absolutely horrible to encode in configuration files. I started seriously doubting if I was really doing the right thing when I saw <if></if>
and <not></not>
tags in my config files. But how else was I supposed to implement abilities that place a debuff (that can do absolutely arbitrary things) provided another debuff is already in place? I've also run into problems with composition: Debuff A was working properly on its own, Debuff B was also working properly on its own, but when both debuffs were placed at the same time there were no longer working properly: it turned out that iterating the list of buffs and debuffs on each turn and applying each of them separately was not always working. So my code grew complex and unwieldy when, in my homebrew config files encoding a debuff I had to test for the presence of other debuffs, etc, etc.
Then I read The Daily WTF article on Soft Coding and I thought I found my error. In fact, my config files syntax grew to become my own programming language, but one that was deeply inferior to what I already had, namely C#. I ditched config files and instead moved all data to .cs
files. It turned out only monsters remained trivially serializable to a data format; abilities, damage types and (de)buffs were so cluttered with logic that it was nigh impossible to serialize them (at least not without creating my own programming language based on XML).
The aforementioned question and answer deals with levels in an SMB-like game. OK, I yield that serializing level data could seem more affordable than, say, serializing enemy data. Still, I think I can foresee imminent difficulties. What if I wanted to put in my level, say, a catapult that can launch 'Mario' to some otherwise inaccessible parts of the map? Note that, inspired by Wario Land, I have put a Rusty Spring as a treasure in this very level; but also I have put a Titanium Powered Adamantium Spring as a treasure in another level. Depending on which spring the hero brings to the catapult, it operates differently. With no spring, it is not functional at all; with a Rusty Spring it launches the hero to a secret area; with Titanium Powered Adamantium Spring it launches the hero to another, even more dangerous bonus area that is filled with even more treasure; with both springs, the player may chose the area they wish to be teleported to.
Not to mention typical various switches, booby traps activating / deactivacting on conditions, NPCs saying different things depending on if you've beaten a boss (or another arbitrarily complex conditions), etc, etc. Level data can easily become cluttered with logic!
If, from the very beginning, I put my level data in config files, I will start banging my head against the wall whenever I decide to implement any of the aforementioned features. If, however, I never touch the 'config files' route and instead always keep level data hardcoded (even when it still seems that this data is trivially serializable) I will not run into problems when I have an idea to implement any of the aforementioned ideas.
Which is probably why level editors in various games typically allow us to define variables and conditions by clicking through their GUI. Essentially, a level editor doubles down as a... visual programming language.
It seems to me that the cost of developing such tools is enormous and should be very carefully weighted against any possible gains from doing so. The situation where making a program (any program, not just a game) more configurable leads to defining and implementing my own programming language (whether by overly complex config files, overly complex config menus or both) should be avoided at all costs.
In particular, if someone just tries making their first game, then this is one of the first features that should be cut (under the general rule to scope smaller).
But even if this is indeed necessary, then game logic should still not be put in config files, but perhaps in Lua code (this is also how, if I'm not mistaken, Factorio can be modded; and also Wesnoth started moving logic in user generated contents from ther Wesnoth Markup Language to Lua).
Do I fail to see something? Why is it recommended that game devs, by default, put their game data in config files? Is it not the case that, over time, these config files will have to store logic rather than just data, making them unwieldy?