Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: LCS Improved Procedural Strings Support (almost)  (Read 3212 times)

IsaacG

  • Bay Watcher
  • Mad Engineer
    • View Profile
    • JJoseph on Deviantart
LCS Improved Procedural Strings Support (almost)
« on: August 18, 2015, 05:47:03 pm »

This mod, as it stand, does not change functionality at all.  This is why I'm not submitting the binary yet, just the source.
(Also, whenever I compile the binary, it's about 10MB for some reason, and I don't know how to control the various options, like music support, which likely relates.)

Anyway, in addition to the slightly reduced filesizes of the source, I have extracted most of the data from the various switch statements and placed them in arrays, making the code notably more readable and easier to modify.  This is especially the case with the pickup lines, as now the pickup lines and responses are kept in the same location.

My intention is to move the data from the arrays into external files.  I have successfully done this with "escapes_running" and "escapes_crawling" as a proof of concept (not included), and I hope to have this finished version submitted here in short order.

The notation to be used is ultimately arbitrary, as well as the filenames and locations of the files containing this XML.  My standing intention is to use a new separate folder to hold these various custom strings, the "art/custom_string" folder, and have created a new class CustomString to control and manipulate these strings (not included, but based off the CreatureTypes class).
This new class also requires the modification of "game.cpp", "externs.h" and "includes.h".  I pulled the source from SVN July 27, and am acting under the assumption these files have not been changed since then, but I intend to post in this thread the exact changes I make in those three files, due to their sensitivity.
The reason I am using a custom class for this purpose, as well as storing the data in XML instead of raw strings, is the occasional logic used in manipulating the data.
A specific example is the death message (paraphrased):
Code: [Select]
addstr("mutters last words")
if(liberal){ addstr(slogan)}
else if(moderate){ addstr("plague on both your houses")}
else { addstr("better dead than liberal")}

The XML I was using would list the preceding as follows:
Code: [Select]
<string>
<line>mutters last words</line>
<line2>better dead than liberal<liberal/ = "slogan"><moderate/ = "plague on both your houses"></line2>
</string>

It's not pretty, so I'm open to suggestions for improvement.  The plan is to use a separate file for each set of custom strings.  One for death messages, one for pickup lines, one for when a character is stunned, one for the custom rejection lines for mutants, one for the custom attacks of judges, etc.  There are about 40 of these at my last count.

So yeah, I intend to have a working prototype in the next few days, and if anyone has any pointers, suggestions, or requests I'm happy to hear them.

I do have two questions for anyone able to answer:
1: how do I get the LCS executable's filesize down to the 500KB or so it normally is, rather than the 10MB I keep getting.  I'm using Visual C++ 2010 SP1, I opened the project file and have been running everything on its default setting (I'm a Java programmer by trade, I'm not used to C++ yet).
2: How do I link a C++ header file to a C++ source.  As it stands I can only get my custom class to compile by placing the source code entirely within the header file, "customstring.h".  So far it's ignoring the "customstring.cpp" I also made.  Java doesn't have header files, and my textbook gives the unhelpful advice "consult your compiler's documentation."

Thank you for your time.

tldr;
This source code is easier to read (ideally) and easier to modify (ideally) but doesn't change any functionality.  I intend add XML files for all the custom strings soon.

Edit:
No more XML, just standard strings, as per advice.
I've updated talk.cpp a little bit, and added interrogation.cpp.
I still haven't got anything for external files, but I expect that's going to all go down at once.

http://www.mediafire.com/download/c094hbdquopncin/talk.cpp
http://www.mediafire.com/download/j7ca23ba8k5tc9b/fight.cpp
http://www.mediafire.com/download/pidz8c3fhcklfpn/interrogation.cpp
http://www.mediafire.com/download/ax3mvqntph9haui/justice.cpp (very few changes, as someone got to it first)

And a dated full rip of the SVN for those interested.
http://www.mediafire.com/download/dz0ue0ixk8nc38x/LCS+Source+20150727.rar
« Last Edit: September 25, 2015, 11:50:56 am by IsaacG »
Logged
LCS 4.12 Thread
https://discord.gg/HYbss8eswM
Quote
Many people, meeting Aziraphale for the first time, formed three impressions: that he was English, that he was intelligent, and that he was gayer than a tree full of monkeys on nitrous oxide.
Constitution of the Confederate States
Article I Sec. 9 4
No bill of attainder, ex post facto law, or law denying or impairing the right of property in negro slaves shall be passe

Purple Gorilla

  • Bay Watcher
    • View Profile
Re: LCS Improved XML Support (almost)
« Reply #1 on: August 19, 2015, 02:35:14 pm »

Congratulation for your change from Java to C, welcome in the halls of true programmers  :D

To your Questions :
* 1 There are two things to reduce the filesize :
** Turn off "include debugging information" from your linker. If you are unsure, if debugging information is included or not, try to debug the programme (use a debugger or IDE). If debugging fails, or you see assembly, then it is not included (what you want), but if it works debugging information is included.
** Use compiler optimization (an option of the compiler). This will cause the compiler to akt more like an assembler programmer instead of strictly following rules. Note, that this will increase the compile time. For this change to take place, you must recompile every file.

* 2 Headers are included with the include command. The brackets do however matter, if you use #include <header.h>, the compilers searches predefined directories (as it does with the standard headers). If you use #include "path\header.h", the compiler expects an exact path. Headers in C work like macros, meaning the line with the  #include command is replaced with the content of the header file. While it is possible to include code with the include command, the normal use is to place code into C files, those objects (the *.obj or *.o files, unrelated to OOP) are linked, and use the headers only for public definitions or macros, those including doesn't produce any machinecode.

------
To your main goal: I am not sure, if placing strings in XML files is a good idea, for three reasons:
* It is inefficient. A lot of time and memory is lost for parsing XML files. LCS already produces bloated savegames, because it saves the characters as XML, that becomes noticable, if you have 200 or so sleepers. A good example for this problems in the large scale is also Dwarf Fortress, that takes a lot of time for parsing the raw files, so even the legends mode takes a long time to load.
* It makes translation harder. English has a very simple grammer, and is mostly gender neutral, so it works to put long sentences into constant strings, while almost every other language needs procedually generated strings. Also, XML doesn't accept characters above 127, so theese need a special encodeing.
* It makes moding harder, because modders must learn XML, if it is too often used.

------
For further information about more optimization, I recommend, to read the source code of the German translation of LCS, wich has already a lot of reduced stringduplication and  optimization :
http://dffd.bay12games.com/file.php?id=10985
Interesting Parts :
* creaturetypes.cpp : I replaced some unfortunate macros (GIVE_WEAPON_CIVILLIAN for example) with functions, to reduce the code-duplication (in the binary) and speed up the compiler. You will see the compile speed, if you try to compile the unmodded creaturetypes.cpp with compiler optimisation, because the compiler will then do the same, but take quite some time.
* politics.cpp : I placed all the text for law changes into one function, to reduce the stringduplication. Interestingly this duplication was related to the bug with crashes on elections.
* shopsandstuff.cpp and shop.cpp : I placed some recurring texts into global variables, to reduce the stringdupplication.
* you can also generally see, the procedual generation of many strings, to properly take care of gender, number and case of all nouns.  In german.c (new file) you can also see, the many different meanings of english word like 'a' 'the' 'his/her' in a language, with multible genders, and multiple cases, that make procedual string generation necessary.

Taberone

  • Bay Watcher
    • View Profile
Re: LCS Improved XML Support (almost)
« Reply #2 on: August 19, 2015, 08:53:31 pm »

Looking nice so far.
Logged

IsaacG

  • Bay Watcher
  • Mad Engineer
    • View Profile
    • JJoseph on Deviantart
Re: LCS Improved XML Support (almost)
« Reply #3 on: August 20, 2015, 05:46:21 pm »

Congratulation for your change from Java to C, welcome in the halls of true programmers  :D
I'm going to pretend I didn't read that.  -.-;

------
To your main goal: I am not sure, if placing strings in XML files is a good idea, for three reasons:
* It is inefficient. A lot of time and memory is lost for parsing XML files. LCS already produces bloated savegames, because it saves the characters as XML, that becomes noticable, if you have 200 or so sleepers. A good example for this problems in the large scale is also Dwarf Fortress, that takes a lot of time for parsing the raw files, so even the legends mode takes a long time to load.
* It makes translation harder. English has a very simple grammer, and is mostly gender neutral, so it works to put long sentences into constant strings, while almost every other language needs procedually generated strings. Also, XML doesn't accept characters above 127, so theese need a special encodeing.
* It makes moding harder, because modders must learn XML, if it is too often used.
Those are some very good points.  When I was working on converting DF raws to true XML I ran into a bunch of problems with the occasional non-ASCII character, and among other reasons was why I stopped before finishing.
My main concern is that many of the strings contain logic, and I'm concerned about how to store this logic if not in XML.
Worst case scenario, I can store the strings in external files, excluding the ones that use logic.  Mainly I'm hoping to make modding easier and allowing custom strings to be stored and modified without requiring the source to be modified, and especially without requiring the binaries to be recompiled.

I'm sold.  I can probably restructure these entirely without using XML.  It'll actually be easier, come to think about it..
Logged
LCS 4.12 Thread
https://discord.gg/HYbss8eswM
Quote
Many people, meeting Aziraphale for the first time, formed three impressions: that he was English, that he was intelligent, and that he was gayer than a tree full of monkeys on nitrous oxide.
Constitution of the Confederate States
Article I Sec. 9 4
No bill of attainder, ex post facto law, or law denying or impairing the right of property in negro slaves shall be passe

Reelya

  • Bay Watcher
    • View Profile
Re: LCS Improved Procedural Strings Support (almost)
« Reply #4 on: August 31, 2015, 03:17:19 am »

I mucked around with refactoring the file on education once and got it down quite a bit, but I didn't commit the edit and I've since lost the file. But from that test edit, I estimate we can knock about 3/4 off a lot of the source code without even putting the data into external files.

I would like to play the game on Android, however the version for Android is way out of date and would be difficult to update. Rebuilding the whole thing for Android, and doing the same for in-code mods would also be a nightmare. It would be great if we could reduce the hard-coded sections and have more external files for functionality, not just for strings but for logic and options. Then it would be easier to port, and also easier to support mods on multiple platforms.

So I'm definitely interested in a joint effort if you're interested, but we'd have to agree on how to collaborate on the work.
« Last Edit: August 31, 2015, 03:20:06 am by Reelya »
Logged

Taberone

  • Bay Watcher
    • View Profile
Re: LCS Improved Procedural Strings Support (almost)
« Reply #5 on: August 31, 2015, 11:39:54 pm »

Will the improved XML support work with the unofficial R855 release of LCS that adds in music and gameplay tweaks?
Logged

IsaacG

  • Bay Watcher
  • Mad Engineer
    • View Profile
    • JJoseph on Deviantart
Re: LCS Improved Procedural Strings Support (almost)
« Reply #6 on: September 02, 2015, 01:54:12 pm »

I mucked around with refactoring the file on education once and got it down quite a bit, but I didn't commit the edit and I've since lost the file. But from that test edit, I estimate we can knock about 3/4 off a lot of the source code without even putting the data into external files.
So far all I've done is refactoring, so I can see where you're coming from.  There's just so much redundancy...  Very few of the strings are legitimately reused, but once they're all out of the way, it gets a lot easier to simplify the code.

I would like to play the game on Android, however the version for Android is way out of date and would be difficult to update. Rebuilding the whole thing for Android, and doing the same for in-code mods would also be a nightmare. It would be great if we could reduce the hard-coded sections and have more external files for functionality, not just for strings but for logic and options. Then it would be easier to port, and also easier to support mods on multiple platforms.

So I'm definitely interested in a joint effort if you're interested, but we'd have to agree on how to collaborate on the work.
I'm interested, in principle.  You may have noticed my responses tend to be... delayed.  My internet connection is limited, I only have access for eight hours a day, four days a week, three weeks a month.
That said, it's quite consistent.
I'm ambivalent about transferring the logic to external files, as that would make the game largely interpreted rather than compiled, which could make debugging a lot harder, but that is something I've always wanted to learn how to do.
I'm up for it.
Edit: Also, I already know Java, and I hear Android is quite similar.

Will the improved XML support work with the unofficial R855 release of LCS that adds in music and gameplay tweaks?
I took the source code directly from SVN on July 27, 2015.  I am of the impression that is the R855 release of which you speak.
That said, in order to complete the procedural string support, I will need to modify the central game loop and recompile the binary.  Thus, compatibility doesn't mean anything in this context.
That said, improving compatibility is sort of a goal, that's why I'm submitting source files instead of compiled binaries.  So long as the mod in question has not modified the files I submit, they can be swapped out without a hitch.
Unfortunately I will eventually need to modify the game.cpp, includes.cpp, and externs.cpp, which pretty much have to be modified in pretty much every mod, which will break compatibility.
« Last Edit: September 02, 2015, 01:56:08 pm by IsaacG »
Logged
LCS 4.12 Thread
https://discord.gg/HYbss8eswM
Quote
Many people, meeting Aziraphale for the first time, formed three impressions: that he was English, that he was intelligent, and that he was gayer than a tree full of monkeys on nitrous oxide.
Constitution of the Confederate States
Article I Sec. 9 4
No bill of attainder, ex post facto law, or law denying or impairing the right of property in negro slaves shall be passe

Reelya

  • Bay Watcher
    • View Profile
Re: LCS Improved Procedural Strings Support (almost)
« Reply #7 on: September 06, 2015, 06:38:06 am »

When I'm talking about reducing the logic to data structures, it can take many forms, for example one change I made to how education works before was to put all the classes in a table, and have the display code work out how many screen pages to use and which ones per page. So that sort of thing makes it much easier to add new things to the education system, you just add another row to a table rather than have to dig down and manually change the screen output and letter-bindings for the existing classes. That kind of thing should make mods much simpler, and it avoids accidentally adding bugs since you're not hitting that many lines of code.

The file I worked on before as a proof of concept was basemode/activate.cpp so I'm going to take a look at that again for this project.

EDIT: I just modified activate.cpp so that the lessons are in a table, and everything is handled by loops in the minimal amount of code. The advantage is that you can add or remove subjects from the lessons without touching the code itself, you just change the lesson codes or the labels, add or remove whole subjects from the table quickly, and the code does the work for you and handles input numbers and the right amount of lesson pages based on how many there are. The outcome in terms of lines of code, it reduced the number of lines of code in the project by about 70.
« Last Edit: September 06, 2015, 12:52:16 pm by Reelya »
Logged

IsaacG

  • Bay Watcher
  • Mad Engineer
    • View Profile
    • JJoseph on Deviantart
Re: LCS Improved Procedural Strings Support (almost)
« Reply #8 on: September 08, 2015, 02:45:30 pm »

When I'm talking about reducing the logic to data structures, it can take many forms, for example one change I made to how education works before was to put all the classes in a table, and have the display code work out how many screen pages to use and which ones per page.
Ah.  I'm tempted to argue that a table is just a 2-d array, but that would be pedantic.

The file I worked on before as a proof of concept was basemode/activate.cpp so I'm going to take a look at that again for this project.

EDIT: I just modified activate.cpp so that the lessons are in a table, and everything is handled by loops in the minimal amount of code. The advantage is that you can add or remove subjects from the lessons without touching the code itself, you just change the lesson codes or the labels, add or remove whole subjects from the table quickly, and the code does the work for you and handles input numbers and the right amount of lesson pages based on how many there are. The outcome in terms of lines of code, it reduced the number of lines of code in the project by about 70.
That sounds excellent.  Now that I think about it, there are quite a few portions where the code would do well in table form, even just in the segments I'm familiar with.
Where can I get a copy of your modified activate.cpp?
Logged
LCS 4.12 Thread
https://discord.gg/HYbss8eswM
Quote
Many people, meeting Aziraphale for the first time, formed three impressions: that he was English, that he was intelligent, and that he was gayer than a tree full of monkeys on nitrous oxide.
Constitution of the Confederate States
Article I Sec. 9 4
No bill of attainder, ex post facto law, or law denying or impairing the right of property in negro slaves shall be passe

Reelya

  • Bay Watcher
    • View Profile
Re: LCS Improved Procedural Strings Support - sample
« Reply #9 on: September 08, 2015, 03:02:20 pm »

A table and a 2D array are not interchangeable concepts. 2D arrays have only one data type, whereas for a table, each field can be a different data type. So you can't emulate a proper data table with a 2D array, unless you only have one type of data in the table. If you want to relate strings, ints, pointers or chars together in a table-like format, you need to make a struct with a constructor for each row.

I'll provide what I've been working on later today. I have my other project I'm working on, which is almost wrapped up for now,  and have to go away for a few days starting tomorrow to help with a friend's game jam, so I'll wrap up what I was editing last and provide the working part before I need to travel.

Here's a pastebin of the edits i did for activate.cpp. I can cut this down a bit more, but I have to get ready for my travel.

http://pastebin.com/ZWzmWSQY

There are basically three main tables I added. One is for what are lessons in the university, one is for which flavor text goes with each activity code (also allows skill-based modifiers for any task), and the third one is a condensation of the menu options for each letter-code. It currently controls what options are displayed for each category. the remaining switch which controls you choosing a task can be rewritten to use this table. too, and that will have the added benefit of only needing to change the table once, and the new option will work for both display and selection.

One advantage with the system I built is the speed of adding new dynamic flavor text. If you want e.g. to make prostitution give different flavor text based on Seduction skill (similar to how art and music text work), well now you don't even need to touch "code" at all, you just write three variations of the text then add the code for the seduction skill onto the end of the line.

These changes knock about 400 lines of code out of the project, as well as making the data more easy to see and edit. We can definitely knock several thousand lines of code off the project, even without making individual files incompatible with other files in the trunk version.

Just working off "activate.cpp" there are plenty of more optimizations than can be made. One useful one would be to get rid of the long-list of creature types used when working out what to teach other liberals. The existence of this system means you have to ensure that every new creature is added to this bit of code. A better system would be to find the current creatures highest skill and then "switch" based on that. That would be better since the skill system won't change very often compared to what creatures you might want to add.
« Last Edit: September 09, 2015, 02:58:19 am by Reelya »
Logged

IsaacG

  • Bay Watcher
  • Mad Engineer
    • View Profile
    • JJoseph on Deviantart
Re: LCS Improved Procedural Strings Support - sample
« Reply #10 on: September 12, 2015, 11:52:05 am »

A table and a 2D array are not interchangeable concepts. 2D arrays have only one data type, whereas for a table, each field can be a different data type. So you can't emulate a proper data table with a 2D array, unless you only have one type of data in the table. If you want to relate strings, ints, pointers or chars together in a table-like format, you need to make a struct with a constructor for each row.
True, I'd forgotten about type safety.  I guess if you override type safety you can still use a 2D array as a table, but that's kind of like using bolt cutters to clip your toenails.
I've been looking over the code a bit, and using a struct allows you to include the various enumerators or constants throughout the code, which is a great idea I hadn't considered.  I was working out how to use a map, but a variable struct could take the place of my partially empty arrays.  That way I won't have to add a conditional to test individual strings.

Also, my C++ book is terrible.  I'm glad to have some code that explains how to make structs instead of having to rely on it.
« Last Edit: September 12, 2015, 11:54:34 am by IsaacG »
Logged
LCS 4.12 Thread
https://discord.gg/HYbss8eswM
Quote
Many people, meeting Aziraphale for the first time, formed three impressions: that he was English, that he was intelligent, and that he was gayer than a tree full of monkeys on nitrous oxide.
Constitution of the Confederate States
Article I Sec. 9 4
No bill of attainder, ex post facto law, or law denying or impairing the right of property in negro slaves shall be passe