Bay 12 Games Forum

Other Projects => Curses => Topic started by: SlatersQuest on December 09, 2013, 11:48:54 am

Title: Modding questions
Post by: SlatersQuest on December 09, 2013, 11:48:54 am
Hello,

I guess it was only a question of time before I started modding.

I'm going to keep this thread and update the opening post (this post) as I get more questions and as existing questions get answered.


Current questions:

4. How does the game generate maps for sieges in safehouses that have existing maps (e.g. university apartments, downtown apartments, captured CCS bases, etc.)?

Answered questions:

1. I'm trying to get the Conservative Crime Squad to attack specific locations, in this case the city park (this is for plot reasons). How do I do this?
Answered in post 2 by Jonathan Fox.
Summary: The indices of the locations[] array is built by the game and does not correspond to the enumerated locations list in locations.h. Instead, there is a find_site_index_in_city() function that will look up an appropriate site. The first argument is the type of location (e.g. SITE_OUTDOOR_PUBLICPARK for the park), and the second is the city (e.g. SITE_CITY_SEATTLE for Seattle, Washington). If the second argument is -1, then the function will simply find the site without bothering for a city (and is ignored if not playing with multiple cities). Also, targeting locations that the CCS is forbidden from raiding (such as the CEO's house) will cause special CCS events.
Notes: also take note of the squadstory_text_location() in squadstory_text.cpp; it has several names, dialogue, etc.

2. Why are several different cities and political issues commented out?
Answered in post 7 by Jonathan Fox.
Summary: Various reasons, but largely that there's no (unique) content for them, either because it was removed from the game for being repetitive (views) or hasn't been added yet (cities)

3. How does the CIA determine whether to justify the CCS' existence if exposed?
Answered by Jonathan Fox in post 12, but see also post 9
Summary: It doesn't. As of this writing (22 December 2013), the FBI will destroy the CCS if it is exposed irrespective of the LCS' behavior prior to the exposure. The wiki is in error (for now).
Title: Re: Modding questions
Post by: KA101 on December 12, 2013, 02:49:32 am
I'd have to say trial/error and take notes?  Let us know--I haven't any idea how to mess with the newspaper.
Title: Re: Modding questions
Post by: Jonathan S. Fox on December 13, 2013, 09:34:40 pm
Hey hey, sorry for not replying sooner. As you've figured out, ns->loc isn't the type of location as defined in locations.h, but the index of a specific location of that type in the locations[] array, and those don't match up; there can be multiple parks in the locations[] array, for example, all sharing the same type as defined in locations.h. Fortunately, there's a function that will track down an index corresponding to the type of location you want:

Code: [Select]
ns->loc = find_site_index_in_city(SITE_OUTDOOR_PUBLICPARK, -1);
As suggested by the function name, the second parameter allows you to pass the city you want to search within (like SITE_CITY_SEATTLE). However, you can pass -1 if you don't care about the city, and the second parameter is ignored either way if you're playing in single city mode. If there are multiple valid locations it could give you an index for, it'll just give you the first one it finds.

Let me know if this works for you or if you're having any other trouble.

Additional Edit: Also, take note of the squadstory_text_location() function in squadstory_text.cpp -- it provides alternate names for several possible locations when showing news stories about CCS hits. So, for example, the CCS won't raid the CEO's House, they'll raid the "Richard Dawkins Food Bank". This could be a source of surprises for you if you set custom CCS raid targets, or alternatively, it could be a target for modding if you want to set up some custom overrides.
Title: Re: Modding questions
Post by: SlatersQuest on December 13, 2013, 11:24:42 pm
Hi Jonathan, thank you very much! I edited the opening post so that other people can easily find your answer!
Title: Re: Modding questions
Post by: SlatersQuest on December 15, 2013, 09:42:30 am
By the way, quick clarification: it's find_site_index_in_city, not find_site_index_by_city, for anybody trying to do the same thing. I'm putting that in the opening post, too. :)
Title: Re: Modding questions
Post by: Jonathan S. Fox on December 15, 2013, 03:25:28 pm
By the way, quick clarification: it's find_site_index_in_city, not find_site_index_by_city, for anybody trying to do the same thing. I'm putting that in the opening post, too. :)

Thanks for the correction, I'll edit my post to avoid having misleading information there too.
Title: Re: Modding questions
Post by: SlatersQuest on December 15, 2013, 05:51:59 pm
Thank you!

I have another question, by the way: looking through the code, I see several pieces of game content that have been commented out. Among them are:

-A couple of laws and views, including VIEW_POLITICALVIOLENCE and VIEW_MILITARY.
-They're not really commented out, but I see location numbers for several cities not currently in the multi-city mode (Detroit, Chicago, Atlanta, Miami).

These are just things I'm seeing. Some of them (especially views on political violence and the military) seem interesting to play with. Is there any particular reason why they're commented out (e.g. are they buggy, just incomplete, or intentionally left out)? What would be the consequences of uncommenting them?

Thanks again!
Title: Re: Modding questions
Post by: Jonathan S. Fox on December 16, 2013, 01:45:05 am
It varies, there isn't any consistent answer for all examples of content that isn't in the game but that some code exists for. There's no content for the unimplemented cities. Political violence is from an earlier version of the game; the design I wrote for the concept ended up being less fun than I'd hoped, so I removed just a couple versions after adding it.

For political issues, many aren't fully implemented, or no gameplay to back them up (eg, some might have no sites to raid), or there could just be low benefit for adding them. There are a lot of views and laws in the game already, and adding more without adding unique gameplay to support them makes the game more grindy (need to do the same action over and over on different issues to win). This has made me hesitant to take the kitchen sink approach to adding new issues. Which is probably more Conservative than Toady would have been (I love how many kinds of rock there are in Dwarf Fortress), but there you have it.
Title: Re: Modding questions
Post by: SlatersQuest on December 18, 2013, 07:40:06 pm
New question: according to the wiki page on the Conservative Crime Squad:

Quote
As of 4.06, you can find a "CCS Backer List" in the CIA computer. Unless your squad has been extremely violent (and we mean extremely), publishing this will cause the CCS to be raided and disbanded within six months. In a few cases, it will just dramatically increase their unpopularity. In the worst of cases, the CIA will justify the CCS as being necessary to stop the LCS (this only happens when you have killed quite a lot of innocent people).

*

I've been searching all over for the code that does this. I have a feeling that I'm not looking for the right thing. Can you maybe tell me where I can find it? Thanks!  :)
Title: Re: Modding questions
Post by: Jonathan S. Fox on December 18, 2013, 08:20:40 pm
Depends on what you're looking for exactly. The meaty stuff destroying the CCS is in news.cpp, but the steps leading up to that are in mapspecials.cpp (getting the backer list) and lcsmonthly.cpp (initially publishing it).

Step 1) src/sitemode/mapspecials.cpp: The LCS raids the Intelligence HQ and activates special_intel_supercomputer(). Upon passing the checks, the global variable ccsexposure is advanced to CCSEXPOSURE_LCSGOTDATA (preventing the LCS from getting two copies of the data), and is provided with a Loot item of type LOOT_CCS_BACKERLIST. (Alternatively, this item can be acquired through a CREATURE_CCS_ARCHCONSERVATIVE sleeper's monthly action, in src/monthly/sleeper_update.cpp.)

Step 2) src/monthly/lcsmonthly.cpp: The LCS is prompted to run a special edition, as in any other month in which they have documents that can be run in the Liberal Guardian. On line 448, the behavior for running LOOT_CCS_BACKERLIST as a special edition is defined, with some specific text and public opinion impacts. But the thing that triggers the eventual downfall is advancing the global variable ccsexposure to CCSEXPOSURE_EXPOSED.

Step 3) src/news/news.cpp: generate_random_event_news_stories() is called each day, and gives a 1 in 60 chance of calling advance_ccs_defeat_storyline() if ccsexposure is in a place where news stories can advance the storyline. advance_ccs_defeat_storyline() makes a news story by calling either ccs_exposure_story() or ccs_fbi_raid_story(), depending on ccsexposure. These are at the end of the file and construct the news story, also doing any extra work needed to implement the effects of the story, like flagging the CCS as destroyed, advancing ccsexposure, arresting your CCS sleepers, etc. The text of the stories are in the middle of the file, in a switch statement over the ns.type of the news story, under the newsstory types NEWSSTORY_CCS_NOBACKERS and NEWSSTORY_CCS_DEFEATED.
Title: Re: Modding questions
Post by: FinetalPies on December 19, 2013, 07:32:52 pm
So is it possible to publish the backer list and have the CCS not disband?
Title: Re: Modding questions
Post by: SlatersQuest on December 21, 2013, 12:52:33 am
Thanks - I was able to find most of these functions, although I didn't understand quite how ccsexposure works. What I was wondering, though, is basically FinetalPies' question: where is the determination that checks to see if the LCS has been so violent that the CCS is justified (and thus the CCS is not eventually destroyed despite the LCS' exposing it)?
Title: Re: Modding questions
Post by: Jonathan S. Fox on December 22, 2013, 12:08:10 am
Thanks - I was able to find most of these functions, although I didn't understand quite how ccsexposure works. What I was wondering, though, is basically FinetalPies' question: where is the determination that checks to see if the LCS has been so violent that the CCS is justified (and thus the CCS is not eventually destroyed despite the LCS' exposing it)?

Oh, there is none, at least in the code I wrote. Someone might have been mistaken!

You could add that, however; you'd just need to track the level of violence the LCS has been engaged in, probably in a global variable somewhere. You'd need to make sure to change saveload.cpp to make it save and load that violence level information!
Title: Re: Modding questions
Post by: SlatersQuest on December 22, 2013, 11:11:05 pm
Got it, thanks!
Title: Re: Modding questions
Post by: SlatersQuest on January 03, 2014, 06:44:56 pm
Hmm... guess I need to ask it here.

The big stumbling block in my path for the Terra Vitae mod is that I don't know how maps are made for sieges, especially in those areas that have maps for them already. For instance, suppose that the LCS takes over the Desert Eagle Bar & Grill and then gets besieged by the CIA... how is the map generated and what determines the LCS' starting position on the map?
Title: Re: Modding questions
Post by: Jonathan S. Fox on January 03, 2014, 11:05:45 pm
You can find the site mode player start location in sitemode.cpp, the mode_site() function places the player. You'll see two major situations, one in which there's no siege (player is given the coordinates (1,1,0) (in x,y,z)), and one in which there is one. In the siege case, the game gives you a random location somewhere on the bottom side of the map; look for the block of code immediately following the comment that talks about a bug involving degenerate spawn locations.
Title: Re: Modding questions
Post by: mosshadow on February 02, 2014, 11:46:21 am
Where are the .cpp files located? I cant find them in the art folder or after decompressing the game file.
Title: Re: Modding questions
Post by: SlatersQuest on February 02, 2014, 02:10:53 pm
The .cpp files are in the src folder (and in folders within the src folder).
Title: Re: Modding questions
Post by: mosshadow on February 02, 2014, 03:01:37 pm
The .cpp files are in the src folder (and in folders within the src folder).

oh nvm im stupid. I had the full version not the source code. I spent a bunch of time trying to open those files with VB to realize i didnt have the source!
Title: Re: Modding questions
Post by: SlatersQuest on February 07, 2014, 04:09:54 pm
Had a question: how do I add new .cpp files (containing new subroutines) to the game? I tried editing the makefile, but my knowledge of C++ is apparently insufficient (I'm running on what I know from ansi-C and carrying it over).
Title: Re: Modding questions
Post by: Carlos Gustavos on February 09, 2014, 08:16:56 am
Makefile.am in the src directory contains a list of all files to compile.
Title: Re: Modding questions
Post by: SlatersQuest on February 09, 2014, 12:52:16 pm
Ah, so there it is. Great, thank you so much! I was looking in the Makefile (where it is for my other source that I've written), and it wasn't there!

Thanks again!  :D
Title: Re: Modding questions
Post by: SlatersQuest on February 28, 2014, 12:39:37 pm
Nevermind - figured it out! :)
Title: Re: Modding questions
Post by: SlatersQuest on March 06, 2014, 01:11:58 pm
All right, I'm stuck.

I have a function that has the following format:

Quote
int FunctionName(Creature *Subject, char *String1, int int1, int int2, int int3, char *String2, int int4, char *String3, char *String4)
{
     int attributelist[ATTNUM];
     int i, juicemodifier, otherstuff;

     ...
}


The moment I enter this function, the values of int2 and int3 get clobbered and turned into huge integers (they look like addresses or converted character strings). What the heck is going on?

Edit: The values of int2 and int3 don't get clobbered until after i and the other integers in the function are initialized. What could be overwriting them?

Edit part II: Something even stranger is going on. When I return from the subroutine, the changes to Subject reflect the original, correct values, even though the Subject itself isn't.
Title: Re: Modding questions
Post by: SlatersQuest on March 06, 2014, 06:58:37 pm
Update:

Apparently, if I enter a subroutine passing an argument of type Creature*, the contents of the creature gets scrambled as I enter the subroutine.

How do I reference a creature inside of a subroutine??
Title: Re: Modding questions
Post by: Carlos Gustavos on March 14, 2014, 10:09:27 am
I can't see anything wrong with what you're showing and passing a Creature* is nothing special. How does your calling code look?
Title: Re: Modding questions
Post by: SlatersQuest on March 14, 2014, 10:29:39 am
Well, after testing it extensively, I think the problem is a bug inside of gdb, rather than inside of LCS. If I use fprintf() to stderr, it prints the right values from the creature going in, but the debugger itself can't access the data. Weird.
Title: Re: Modding questions
Post by: SlatersQuest on July 12, 2014, 10:50:02 am
Hi

I need help.

I've gotten access to a Windows operating system and have downloaded a free Windows C++ compiler to compile the Terra Vitae mod for Windows. However, because LCS has multiple source files, simply directing the compiler to compile any one of them fails. I know that there are people on this board who have compiled the whole thing because the Windows and Unix source files are up on Curses - but how do I compile my Unix source on Windows?

Thank you.
Title: Re: Modding questions
Post by: Liberal Elitist on August 07, 2014, 04:00:18 am
Hi

I need help.

I've gotten access to a Windows operating system and have downloaded a free Windows C++ compiler to compile the Terra Vitae mod for Windows. However, because LCS has multiple source files, simply directing the compiler to compile any one of them fails. I know that there are people on this board who have compiled the whole thing because the Windows and Unix source files are up on Curses - but how do I compile my Unix source on Windows?

Thank you.

Use the Code::Blocks IDE with the TDM-GCC compiler (http://www.codeblocks.org/downloads/26) (choose codeblocks-13.12mingw-setup-TDM-GCC-481.exe as the download, at least with the current version... the filename will be different with the next version obviously). That is free software, as in freedom. Or use Microsoft Visual C++ 2010 Express (http://www.visualstudio.com/downloads/download-visual-studio-vs#DownloadFamilies_4) as both your IDE and compiler. It's proprietary but free as in beer.

Visual C++ 2012 and later by default produce executables that require Windows Vista (I'm on Windows XP) and require CPUs that support SSE2 (mine supports SSE but not SSE2). You can change that default behavior of Visual C++ 2012 and later to make executables that work on Windows XP and have different CPU requirements, but that's a hassle, best to avoid MS Visual C++ 2012 and later unless you want to go through all that hassle.

Personally I just use Code::Blocks with TDM-GCC. Works great for compiling on Windows. Plus GCC is probably what you use on UNIX so it should be something you're used to. But I wouldn't say that there is "UNIX source", the source code is the same for all operating systems, it just uses defines to properly integrate with whatever the operating system and compiler APIs and libraries support. The only difference is the line endings... if you download it from SVN on Unix you'll have Unix-style line endings, while if you download it from SVN on Windows you'll have Windows-style line endings. That doesn't matter for compilation, it just makes things look correct in text editors. It's fairly easy to compile a project in an IDE, that's the way I always do it. There are also makefiles but that's not something I'm any good with.
Title: Re: Modding questions
Post by: SlatersQuest on August 26, 2014, 06:46:57 pm
Hello, I need help with a bug.

I've added three new weapons to the game. They all blow up (cause a segmentation fault in Unix lingo) when the following line of code is run:

Code: [Select]
weapontype[getweapontype(itemtypename())]->get_name(subtype)
The part that is crashing is the getweapontype(itemtypename()) part. getweapontype(const string) has the following code:

Code: [Select]
/* transforms a weapon type name into the index of that weapon type in the global vector */
int getweapontype(const string &idname)
{
   
   
    for(int i=0;i<(int)weapontype.size();i++)
    {
       
        if(weapontype[i]->get_idname()==idname)
        {
            return i;
        }
    }
       
   return -1;
}

The segmentation fault happens upon the return of the function. I have put test statements (consisting of getch() and fprintf statements to stderr) all through this, so I know that getweapontype() works properly up until the moment of returning i, at which point it crashes. I also tried creating a local variable in Weapon::get_name() and setting getweapontype() equal to that before looking up the weapontype[] vector. getweapontype() crashes on returning i, irrespective of whether it is used as an element of weapon type[] or if it is simply returning an int to a local value, and it crashes for all three of my new weapon types - this despite that getweapontype() can see the new weapon types within itself.

Can anybody please help tell me what is going on and how to fix it?

Thanks!
Title: Re: Modding questions
Post by: Liberal Elitist on August 26, 2014, 08:58:47 pm
Hello, I need help with a bug.

I've added three new weapons to the game. They all blow up (cause a segmentation fault in Unix lingo) when the following line of code is run:

Code: [Select]
weapontype[getweapontype(itemtypename())]->get_name(subtype)
The part that is crashing is the getweapontype(itemtypename()) part. getweapontype(const string) has the following code:

Code: [Select]
/* transforms a weapon type name into the index of that weapon type in the global vector */
int getweapontype(const string &idname)
{
   
   
    for(int i=0;i<(int)weapontype.size();i++)
    {
       
        if(weapontype[i]->get_idname()==idname)
        {
            return i;
        }
    }
       
   return -1;
}

The segmentation fault happens upon the return of the function. I have put test statements (consisting of getch() and fprintf statements to stderr) all through this, so I know that getweapontype() works properly up until the moment of returning i, at which point it crashes. I also tried creating a local variable in Weapon::get_name() and setting getweapontype() equal to that before looking up the weapontype[] vector. getweapontype() crashes on returning i, irrespective of whether it is used as an element of weapon type[] or if it is simply returning an int to a local value, and it crashes for all three of my new weapon types - this despite that getweapontype() can see the new weapon types within itself.

Can anybody please help tell me what is going on and how to fix it?

Thanks!

I looked at that code and it does not have any bugs in it (the array index stays within bounds, using const references to std::strings is a very safe programming practice that makes bugs and crashes unlikely, you are simply returning an integer, I don't see anything in that code that could cause a bug, except for one thing... that function calls the get_idname() function of weapontype[i], so perhaps the bug might be there). The bug is probably somewhere else but it does not cause a segfault until that code happens.

Anyway, the problem you encountered, a segmentation fault, is typically caused by using pointers in C/C++. A segmentation fault occurs when software attempts to read or write a location in memory that it does not have permission from the operating system to read or write to. This can be caused by an array/vector/etc. index being out of bounds, dereferencing an uninitialized or NULL pointer, attempting to access an object that has been deleted, or a buffer or stack overflow. In C/C++, arrays are actually implemented as pointers to an area of memory, and the indexing operator [] adds a number to the pointer equal to the size of the objects in the array times the value you are indexing. And vectors are implemented as arrays, and thus ultimately pointers. What is safest is references, as they always have to be initialized and they are not allowed to be NULL.

Anyway, it appears as if, either explicitly or implicitly through how the compiler implemented the code, one of those things happened. So here are the 4 likely culprits:
1) Uninitialized or null pointer/object getting dereferenced/accessed
Code: [Select]
   int *i; // not initialized or allocated
   (*i)++; // this could point to anything... SIGSEGV... Segmentation Fault
2) Array/vector index out of bounds
Code: [Select]
   char c[13]="Conservative"; // we need 13 characters to store this as null-terminated
   addch(c[13]); // if an array is of size 13, its highest index will be 12 so this is out of bounds... SIGSEGV... Segmentation Fault
3) Attempting to access an object that has been deleted/freed (this can even happen with references, if you create a reference to an object pointed to by a pointer, then delete the object, then try to access the reference... normally references are safer than pointers but even they don't protect you from everything)
Code: [Select]
   delete x; // x is deleted, gone, outta here
   gamelog.log(x); // you can't use x, we just deleted it... SIGSEGV... Segmentation Fault
4) Attempting to modify read-only memory (for example trying to the value of something that is const)
Code: [Select]
   char *s="liberal"; // "liberal" is actually implicitly a const expression that the char* pointer s is pointing to, you can't modify it
   *s='L'; // I said, you can't modify it! It's const, even though it doesn't say so explicitly... SIGSEGV... Segmentation Fault

The fact that it occurs when you are returning from this function is interesting... that means it likely has something to do with the code that happens when you enter and leave the function, and variables that change scope... old local variables that are no longer local variables, and new local variables that were local prior to the function call, weren't local inside the function that got called, but are now local again. This could also be the result of strange compiler optimizations or a buggy compiler.

However the 4 likely culprits I listed above, those are probably what caused it, try and look for those. Sometimes, a program can do one of those things and get away with it temporarily, without crashing immediately, and then the crash will happen a bit later on, maybe in a different function... like a ticking time bomb. The memory access violation, the segmentation fault, was probably caused by something that happened earlier, but that the program got away with without being caught, temporarily. And then when trying to return from this function, it suddenly detonates the segmentation fault without any warning, when actually the bug probably happened earlier, before this function was ever called, or maybe inside the function it calls, get_idname() from the WeaponType class.

It appears the WeaponType class populates values from XML, from an XML file. So if you leave out certain values in the XML file, that might trigger a crash because a value would never be populated to a certain variable and it would remain uninitialized.

Still, I don't have enough to go on here, I'll need to see how exactly you added the 3 weapons, and the XML and/or C++ code for that. This type of bug can be a little hard to track down. That is why some people prefer languages such as Java which are designed in such a way as to make this type of bug almost impossible to happen, whereas C/C++ is designed so it's hard to avoid this type of bug happening unless you are perfect and never make mistakes. The benefit of C/C++ over Java, though, is that being able to use pointers, despite their dangerousness, allows you to make programs that run much faster and have less overhead. I am grouping C and C++ together here because when it comes to this type of thing, a segmentation fault, and many other things, the 2 languages are pretty much the same, and the vast majority of C code is also valid C++ code without any alterations (with the C++11 standard adding in the bits from C that were missing from the earlier C++98 standard such as specific-size integer types with specific numbers of bits). C++ does add plenty of stuff to try and make errors like segmentation faults happen less often, for instance you can replace arrays with std::vectors and C-strings with std::strings and pointers with references and that all makes crashes less likely.

I have a pretty strong suspicion this is one of those time-bomb bugs where something bad happens earlier but the compiler didn't catch it when compiling, the operating system didn't catch it when it executed, and some earlier code left you a time-bomb segmentation fault bug that got triggered later on. Ah, I think I have it... when you leave a function, it gets rid of the local variables and other function call overhead that is stored in memory. Well, what must have happened is, the earlier time-bomb made certain memory locations, shall we say, unsuitable for use, and then this function got called and used them, and when the function tried to return and free up that memory, it couldn't, because of some unsavory activity that happened at those memory locations previously... namely an uninitialized pointer/object being dereferenced/accessed, an array/vector index out of bounds, or attempting to access an object that had been deleted. That happened in a certain memory location and made it "dirty", and then this function used memory in the "dirty" location and triggered the error.
Title: Re: Modding questions
Post by: SlatersQuest on August 27, 2014, 07:33:28 am
Okay, I think I may know what you mean - I may have inadvertently overwritten an address of something in adding or freeing memory. I've done that in C before and it makes weird bugs.

Here's the code that makes the three weapons:

XML:
Code: [Select]
    <weapontype idname="WEAPON_MAGIC">
        <name>Magic Spells</name>
        <name_future>The Force</name_future> <!-- Star Wars -->
        <shortname>Magic</shortname>
        <shortname_future>Force</shortname_future>
        <can_take_hostages>true</can_take_hostages>
        <protects_against_kidnapping>true</protects_against_kidnapping>
        <threatening>true</threatening>
        <instrument>true</instrument>
        <graffiti>true</graffiti>
        <legality>1</legality>
        <bashstrengthmod>200</bashstrengthmod>
        <auto_break_locks>true</auto_break_locks>
        <suspicious>false</suspicious>
        <size>0</size>
        <attack>
            <priority>1</priority>
            <ranged>true</ranged>
            <attack_description>evokes a spell at</attack_description>
            <hit_description>smiting</hit_description>
            <skill>MAGIC</skill>
            <accuracy_bonus>6</accuracy_bonus> <!--Point and ensorcel-->
            <can_backstab>true</can_backstab>
            <random_damage>66</random_damage>
            <fixed_damage>66</fixed_damage>
            <burns>true</burns>
            <severtype>NASTY</severtype>
            <armorpiercing>8</armorpiercing>
            <critical>
                <chance>20</chance>
                <random_damage>666</random_damage>
                <fixed_damage>666</fixed_damage>
            </critical>
            <fire>
                <chance>20</chance>
                <chance_causes_debris>30</chance_causes_debris>
            </fire>
        </attack>
        <attack>
            <priority>2</priority>
            <ranged>false</ranged>
            <attack_description>swings a magical blade at</attack_description>
            <hit_description>striking</hit_description>
            <skill>MAGIC</skill>
            <accuracy_bonus>4</accuracy_bonus> <!--Magic sword skill-->
            <can_backstab>true</can_backstab>
            <strentgh_min>4</strentgh_min>
            <strength_max>20</strength_max>
            <random_damage>144</random_damage>
            <fixed_damage>12</fixed_damage>
            <burns>true</burns>
            <cuts>true</cuts>
            <severtype>CLEAN</severtype>
            <armorpiercing>4</armorpiercing>
            <critical>
                <chance>20</chance>
                <random_damage>432</random_damage>
            </critical>
        </attack>
    </weapontype>
   
    <weapontype idname="WEAPON_POWERS">
        <name>Superhuman Powers</name>
        <shortname>Powers</shortname>
        <can_take_hostages>true</can_take_hostages>
        <protects_against_kidnapping>true</protects_against_kidnapping>
        <threatening>true</threatening>
        <instrument>true</instrument>
        <legality>2</legality>
        <bashstrengthmod>500</bashstrengthmod>
        <suspicious>false</suspicious>
        <size>0</size>
        <attack>
            <priority>1</priority>
            <ranged>true</ranged>
            <attack_description>fires a super-blast at</attack_description>
            <hit_description>striking</hit_description>
            <skill>POWERS</skill>
            <accuracy_bonus>0</accuracy_bonus>
            <random_damage>300</random_damage>
            <fixed_damage>25</fixed_damage>
            <bruises>true</bruises>
            <burns>true</burns>
            <severtype>NASTY</severtype>
            <armorpiercing>1</armorpiercing>
            <fire>
                <chance>15</chance>
                <chance_causes_debris>50</chance_causes_debris>
            </fire>
        </attack>
        <attack>
            <priority>2</priority>
            <ranged>false</ranged>
            <attack_description>punches with superhuman strength at</attack_description>
            <hit_description>striking</hit_description>
            <skill>POWERS</skill>
            <accuracy_bonus>2</accuracy_bonus>
            <strentgh_min>4</strentgh_min>
            <strength_max>20</strength_max>
            <can_backstab>true</can_backstab>
            <random_damage>101</random_damage>
            <fixed_damage>12</fixed_damage>
            <bruises>true</bruises>
            <severtype>NASTY</severtype>
        </attack>
    </weapontype>
   
    <weapontype idname="WEAPON_BATTLESUIT">
        <name>Battlesuit Blasters</name>
        <shortname>Blasters</shortname>
        <can_take_hostages>true</can_take_hostages>
        <protects_against_kidnapping>true</protects_against_kidnapping>
        <threatening>true</threatening>
        <instrument>true</instrument>
        <legality>-2</legality>
        <bashstrengthmod>500</bashstrengthmod>
        <suspicious>true</suspicious>
        <size>20</size>
        <attack>
            <priority>1</priority>
            <ranged>true</ranged>
            <attack_description>fires an energy blast at</attack_description>
            <hit_description>striking</hit_description>
            <skill>BATTLESUIT</skill>
            <accuracy_bonus>3</accuracy_bonus>
            <random_damage>25</random_damage>
            <fixed_damage>250</fixed_damage>
            <burns>true</burns>
            <severtype>NASTY</severtype>
            <armorpiercing>5</armorpiercing>
            <fire>
                <chance>25</chance>
                <chance_causes_debris>45</chance_causes_debris>
            </fire>
        </attack>
        <attack>
            <priority>2</priority>
            <ranged>false</ranged>
            <attack_description>swings an armored fist at</attack_description>
            <hit_description>striking</hit_description>
            <skill>BATTLESUIT</skill>
            <accuracy_bonus>0</accuracy_bonus>
            <strentgh_min>2</strentgh_min>
            <strength_max>10</strength_max>
            <random_damage>201</random_damage>
            <fixed_damage>80</fixed_damage>
            <bruises>true</bruises>
            <severtype>NASTY</severtype>
        </attack>
    </weapontype>
   


In Creature.h:

Quote
class Creature
{
...

    bool is_unarmed() const { return weapon == NULL; }
    bool is_armed() const;

...
}


In Creature.cpp:

Quote

Weapon& Creature::get_weapon() const
{
    //Terra Vitae: modified to account for magic
   if (!is_unarmed())
       return *weapon;
   else if (get_skill(SKILL_MAGIC) > 0)
       return weapon_magic();
   else if (get_skill(SKILL_POWERS) > 0)
       return weapon_powers();
   else if (get_armor().get_itemtypename() == "ARMOR_BATTLESUIT")
       return weapon_suit();
   else
      return weapon_none();
}

bool Creature::is_armed() const
{
        //Terra Vitae function
    if (get_weapon().get_itemtypename() == "WEAPON_NONE")
        return false;
    else
        return true;
}

...



Weapon& Creature::weapon_magic() const
{
    static Weapon* magic = new Weapon(*weapontype[getweapontype("WEAPON_MAGIC")]);
    return *magic;
}

Weapon& Creature::weapon_powers() const
{
    static Weapon* powers = new Weapon(*weapontype[getweapontype("WEAPON_POWERS")]);
    return *powers;
}

Weapon& Creature::weapon_suit() const
{
    static Weapon* battlesuit = new Weapon(*weapontype[getweapontype("WEAPON_BATTLESUIT")]);
    return *battlesuit;
}
Title: Re: Modding questions
Post by: SlatersQuest on August 30, 2014, 10:28:29 am
Um, does this help?

I'm thinking of possibly removing the new "weapons" and editing the existing "Unarmed" weapon, if I can't find a solution otherwise.
Title: Re: Modding questions
Post by: Liberal Elitist on September 10, 2014, 07:03:01 am
I'll look at that code later when I have the time.
Title: Re: Modding questions
Post by: Liberal Elitist on September 10, 2014, 12:18:07 pm
OK I suggest you change the weapon_magic(), weapon_powers(), and weapon_suit() functions to use references instead of pointers internally, the way weapon_none() and armor_none() work. This way the object they return a reference to will be a statically declared object guaranteed to exist rather than an object from a dereferenced pointer to an object created using a constructor. Look at the way weapon_none() and armor_none() are implemented:

Code: [Select]
Weapon& Creature::weapon_none()
{
   static Weapon unarmed(*weapontype[getweapontype("WEAPON_NONE")]);
   return unarmed;
}

Armor& Creature::armor_none()
{
   static Armor naked(*armortype[getarmortype("ARMOR_NONE")]);
   return naked;
}

That is very good code in the existing implementations of weapon_none() and armor_none() that you should copy as closely as possible for your new functions. You should do weapon_magic(), weapon_powers(), and weapon_suit() the exact same way, using references instead of pointers, and rather than having them be const functions, make them static functions in the header:

Use this in creatures.cpp:

Code: [Select]
Weapon& Creature::weapon_magic()
{
    static Weapon magic(*weapontype[getweapontype("WEAPON_MAGIC")]);
    return magic;
}

Weapon& Creature::weapon_powers()
{
    static Weapon powers(*weapontype[getweapontype("WEAPON_POWERS")]);
    return powers;
}

Weapon& Creature::weapon_suit()
{
    static Weapon battlesuit(*weapontype[getweapontype("WEAPON_BATTLESUIT")]);
    return battlesuit;
}

Also look at the declarations for weapon_none() and armor_none() in creatures.h in the current code:

Code: [Select]
class Creature
{
private:

...

   static Weapon& weapon_none();
   static Armor& armor_none();

...

Note how both of them are declared static functions in the private section of the class, in the header file. Do the same thing with weapon_magic(), weapon_powers(), and weapon_suit() in creature.h:

Code: [Select]
class Creature
{
private:

...

   static Weapon& weapon_magic();
   static Weapon& weapon_powers();
   static Weapon& weapon_suit();

...

That oughta fix this segfault thing right up! ;D
Title: Re: Modding questions
Post by: SlatersQuest on September 10, 2014, 05:49:40 pm
Gah, no, it still causes a segfault, all three weapons. Here's what the code looks like now:

Code: [Select]
Weapon& Creature::weapon_none() const
{
    static Weapon* unarmed = new Weapon(*weapontype[getweapontype("WEAPON_NONE")]);
    return *unarmed;
}

Weapon& Creature::weapon_magic() const
{
    static Weapon magic(*weapontype[getweapontype("WEAPON_MAGIC")]);
    return magic;
}

Weapon& Creature::weapon_powers() const
{
    static Weapon powers(*weapontype[getweapontype("WEAPON_POWERS")]);
    return powers;
}

Weapon& Creature::weapon_suit() const
{
    static Weapon battlesuit(*weapontype[getweapontype("WEAPON_BATTLESUIT")]);
    return battlesuit;
}

Armor& Creature::armor_none() const
{
   static Armor* naked = new Armor(*armortype[getarmortype("ARMOR_NONE")]);
   return *naked;
}


I note that weapon_none() and armor_none() do use the new weapon/armor (which is the code that I acquired when I downloaded LCS for the first time last fall)... and weapon_none() does *not* cause a segfault in this configuration.
Title: Re: Modding questions
Post by: Liberal Elitist on September 11, 2014, 01:18:09 pm
Gah, no, it still causes a segfault, all three weapons. Here's what the code looks like now:

Code: [Select]
Weapon& Creature::weapon_none() const
{
    static Weapon* unarmed = new Weapon(*weapontype[getweapontype("WEAPON_NONE")]);
    return *unarmed;
}

Weapon& Creature::weapon_magic() const
{
    static Weapon magic(*weapontype[getweapontype("WEAPON_MAGIC")]);
    return magic;
}

Weapon& Creature::weapon_powers() const
{
    static Weapon powers(*weapontype[getweapontype("WEAPON_POWERS")]);
    return powers;
}

Weapon& Creature::weapon_suit() const
{
    static Weapon battlesuit(*weapontype[getweapontype("WEAPON_BATTLESUIT")]);
    return battlesuit;
}

Armor& Creature::armor_none() const
{
   static Armor* naked = new Armor(*armortype[getarmortype("ARMOR_NONE")]);
   return *naked;
}


I note that weapon_none() and armor_none() do use the new weapon/armor (which is the code that I acquired when I downloaded LCS for the first time last fall)... and weapon_none() does *not* cause a segfault in this configuration.

Umm, are you SURE that the segfaults are coming from the 3 new weapons, and not the code for weapon_none() or armor_none() that you have there? Maybe try having ALL FIVE of those functions avoid using pointers or the "new" keyword and be "static" functions as declared in the header, instead of "const" functions. The code for weapon_none() and armor_none() there looks rather off. It might not cause segfaults but that code will DEFINITELY cause memory leaks, just fix it to not use pointers, and to be "static" instead of "const", OK? Otherwise it'll cause a memory leak... doesn't crash your program like a segfault does but it gradually eats up more and more memory the longer the program runs.

Anyway as for the segfault it's probably caused by your XML then. I haven't looked at it yet actually, I just looked at your C++ source code. The way XML stuff is parsed, it's possible that might cause a segfault too, maybe, I'm not sure. I'll need to look closer at it. But you should fix that memory leak anyway even if I don't know the cause of the segfault yet and if my previous guess about what was causing the segfault was wrong... sorry about that, it was just a memory leak I found, not a segfault, and segfaults are worse problems than memory leaks. So the XML parsing code might be generating weapons that might have some things uninitialized or something like that, leading to segfaults.

Well to fix this I will probably have to download your code and try it out myself in a compiler and debug it. I was just eyeballing the code you posted in the forums but that doesn't seem to be catching the cause of these segfaults. So I'll download your latest source code and see if I can get it working.

So do you suggest I download the source code for version 0.1 of the Terra Vitae mod from the first post in the Terra Vitae thread (http://www.bay12forums.com/smf/index.php?topic=134632.0)? Or do you have more updated code you'd prefer I download? It seems if I debug this I'll have to do it for real and actually compile, build, and run the code and debug it, instead of just looking at code you post on the forums. And to do that correctly I'd need to use all the source code you're using as part of your codebase, since it's a different codebase than the vanilla game and it's essentially forked from a version you downloaded last fall rather than kept as a diff patch against the current source code. Anyway if the bug is present in version 0.1 I ought to just be able to download that and try and debug it, I don't think I'll need you uploading a different version for me... if version 0.1 has that bug then I'll be able to debug it hopefully.

Well it looks like this'll be harder to solve than I thought. Sorry my hunch about what was causing a segfault was wrong and that I had only found something that caused memory leaks. You should still fix those memory leaks by doing those code changes I said except this time do it to weapon_none() and armor_none(). Thanks.
Title: Re: Modding questions
Post by: Liberal Elitist on September 11, 2014, 03:58:56 pm
OK SlatersQuest I had to make some changes to get it to compile correctly on Code::Blocks with the MinGW compiler using the current settings I use (for strict ANSI C++98 compliance to help catch more bugs) and I am wondering if you want the updated code for your mod. I also fixed all the compiler warnings that came up. You had a bunch of compiler warnings for code in additionalchars.cpp. It doesn't look like the code in that file is very tested or stable but at least I fixed all the compiler warnings for it, now the program compiles without any warnings. But I think the bug might be in additionalchars.cpp.

So if you've made any progress since version 0.1 of Terra Vitae I'd like the updated code so that I can apply my fixes to it. Then after I fix it I can send the code back to you again. But I'm going to work on a bigger set of fixes... and try to get this segfault thing fixed. I don't know how to duplicate the bug though. After compiling and building the game and fixing the compiler warnings I got the game up and running and I noticed you have more skills, more potential crimes, more cities and safehouses, but the game seems mostly the same besides that so far. I need to know how to duplicate this bug though.

Also I've determined your code is based on revision 739 from October 25, 2013 posted by me (yetisyny), although it also does contain the bugfix from revision 746 of the code, from April 8, 2014 posted by blomkvist (although in the changelog he credits YOU with that fix... good job!). Changes from later revisions don't seem to be in it, but changes from earlier revisions do seem to be in it. Maybe it might be possible to make your code be based on a more recent revision or even the current code (currently at revision 843), to include bugfixes done since then as well as new features. Of course that's up to you, whether you want that or not. But, you are currently 104 revisions behind the current revision... a lot of bugs have been fixed and features added in that time, to the vanilla game, that would also enhance your mod. But you might not want the Stalinist Comrade Squad incomplete feature added to it... still I think a lot of the code from that might be useful for your mod, you would just rename it something like Terra Vitae instead of Stalinist.

But yeah anyway I need to know if you've made changes since the 0.1 release besides what I suggested here so I can incorporate them with the fixes I've made to your code and then send it back to you so that you can have Terra Vitae with fixes. So far it's just fixes for compiling in Code::Blocks and GCC using the current settings used by the main project (strict ANSI mode being the main thing... I got your code in compliance with the strict ANSI C++98 standard, which is a compilation option on GCC).

Also the code in additionalchars.cpp is a bit suspicious to me. I wonder if maybe it is the source of the bug. It had several compiler warnings. There were unused variables, variables whose values were used even when they might not be initialized, and functions that were supposed to return values of type "int" that didn't have any return statements at all. It doesn't have any compiler warnings anymore now that I fixed them. I even fixed some minor bugs with the cheat codes in it. But I think it has more bugs and I am probably just scratching the surface of the bugs in that file. Also that file's comments at the beginning say it was created by Chris Johnson when actually it was created by you, SlatersQuest. Anyway I think I might be able to find it but actually I've already found and fixed some smaller bugs, not very many though, I haven't found and fixed this major segfault bug yet.

So I need you to tell me how to reproduce the bug please. And also give me your most up-to-date code please, if you've made any changes since version 0.1 of Terra Vitae. Since I am trying to fix the bugs in it now that I have the source code and compiled and built it myself. Hmm... maybe I could diff your code against revision 739 now that I know it's based on that, and then put together a list of all the changes you made to each file, and then use those diffs and apply them to the latest SVN revision of the game, to make your code up-to-date. If you want me to, that is.

Of course I am going on vacation later this month and will be offline for about a month, traveling in Austria and Italy (specifically the city of Vienna and the island of Sicily). So I won't be available then or be doing any programming then. I will be available again after I come back to the United States in mid-to-late October. I think I have about 12 days left before I leave.
Title: Re: Modding questions
Post by: SlatersQuest on September 11, 2014, 05:46:13 pm
Memory leaks fixed, segfaults still happen, new version (0.11) uploaded!

I actually made quite a few changes since the last release (and, as soon as this bug is fixed, I was going to upload version 0.2). I really appreciate your looking at this - I wish you had waited for my last response, because all of the warnings from additionalchars.cpp have been fixed now!

Ugh - this is one of those situations where I'm kinda out of my league. Prior to this project, I had worked with ansi C, never C++ - which is why I don't understand the deeper aspects of references and pointers that well...
Title: Re: Modding questions
Post by: Liberal Elitist on September 12, 2014, 02:23:07 pm
Memory leaks fixed, segfaults still happen, new version (0.11) uploaded!

I actually made quite a few changes since the last release (and, as soon as this bug is fixed, I was going to upload version 0.2). I really appreciate your looking at this - I wish you had waited for my last response, because all of the warnings from additionalchars.cpp have been fixed now!

Ugh - this is one of those situations where I'm kinda out of my league. Prior to this project, I had worked with ansi C, never C++ - which is why I don't understand the deeper aspects of references and pointers that well...

I downloaded the new version from http://dffd.wimbli.com/file.php?id=8634 (http://dffd.wimbli.com/file.php?id=8634) and although it says version 0.11 on that webpage, it also says "Last Updated: Jun 11, 2014, 12:00:45 am"... 3 months ago. And I did a binary file comparison on the .zip file I downloaded of version 0.11 and the .zip I previously downloaded of version 0.1 and the files are identical, every single bit of data is the same.

Looks like if you DID upload a new version there, maybe that site takes a little while to process uploads and isn't making it available quite yet... maybe in a day or two that site will update the download to be the latest version you uploaded. I'm not sure what's going on with that.

But anyway if you fixed those memory leaks that's great. And also if you've used ANSI C before, well that's also really great because C++ preserves 99% of the features of ANSI C and adds a whole bunch more, meaning most valid C code is valid C++ code and the only major exception to this is if you use the integer types that take up a fixed number of bits of data (int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, and uint64_t).

Anyway I'm trying to duplicate the bug with the segfault and trying to get cheat codes to work like I mentioned in the other thread. I am rather confused right now by the source code saying one thing but when I try it out in the game it doesn't happen like I think it should when I look at the source code. I am too confused for this right now... :o
Title: Re: Modding questions
Post by: SlatersQuest on September 12, 2014, 07:55:32 pm
Yeah, DFFD played some shenanigans on us. I just re-re-re-re-uploaded the 0.11 version, re-downloaded it, and tested it. It should be good now.

Again, sorry for the confusion and thanks for your help!
Title: Re: Modding questions
Post by: SlatersQuest on October 02, 2014, 09:47:33 pm
Am I correct in that VIEW_JUSTICES doesn't actually do anything to the game (apart from being yet another view upon which elections are based, that is)?

:)
Title: Re: Modding questions
Post by: Liberal Elitist on October 03, 2014, 01:01:56 pm
Am I correct in that VIEW_JUSTICES doesn't actually do anything to the game (apart from being yet another view upon which elections are based, that is)?

:)

Well not currently but it ought to! Specifically, it ought to affect Supreme Court nominations. I think that is the intention for it anyhow. Basically moderates in Congress or the White House would be very likely to be swayed by public opinion on what kind of justices should be on the courts, while extremists of any stripe (be they Elite Liberal, Arch-Conservative, Stalinist, or any other type of extremist we ever add to the game) are not swayed at all by public opinion. And regular Liberals and regular Conservatives would have a bit of a chance to be swayed by public opinion rather than going with their own political alignment, not as much as moderates though. Anyway this is what VIEW_JUSTICES is supposed to actually affect... Supreme Court nominations. This is just a feature that has not yet been implemented. You should remind me to implement it later... or maybe I can remind myself, by looking through and re-reading what I wrote here in this thread, when I get back from vacation. There is a slight complication when you consider Stalinist mode... VIEW_JUSTICES, like all the other views, ranges from Arch-Conservative when it is 0 to Elite Liberal when it is 100, but that does not take into account public views on Stalinism. So when Stalinist mode is off, moderates would only look at VIEW_JUSTICES. When it is on, they might also look at VIEW_STALIN too. Well maybe not. Because I think a moderate or regular Conservative or regular Liberal is only swayed by 1 away from their own alignment by public opinion (like if the public is 100% Elite Liberal and you have a regular Conservative in Congress, this would make them vote for a moderate... but not sway them by more than 1 from their alignment). And the alignment of Stalinists is -3, compared to -2 for Arch-Conservatives, -1 for regular Conservatives, 0 for moderates, +1 for regular Liberals, and +2 for Elite Liberals. So only Stalinist members of Congress would ever vote for Stalinist court members because anyone with an alignment in the -1 thru 0 thru 1 range would only be able to be swayed plus or minus 1 with their alignment, not far enough to get them to -3. So taking into account VIEW_STALIN is probably unnecessary here, only VIEW_JUSTICES is necessary to look at for this when consulting public opinion. I will probably implement this feature in the future, having public opinion on VIEW_JUSTICES be consulted for Supreme Court nominations, by both the White House and all 100 of the Senators. And also I think the White House needs to consult popular opinion more when laws are under consideration, too. It does do that in the real world after all. Right now White House behavior is just consulting all 4 members of the executive branch (President, Vice President, Secretary of State, and Attorney General) as well as the Random Number God, but not public opinion, only Congress looks at public opinion currently, not the White House or Supreme Court. Obviously the Supreme Court should NEVER look at public opinion, the real-life version never does, never has, and probably never will, but the White House does, and always has, at least in the real world, so it probably should in the game too. At least, people in the White House who are moderate rather than extreme should consult public opinion. Extremists, as well as Supreme Court justices of any stripe, have no concern with public opinion and do as they please. Which is why Supreme Court nominations matter so much, and why VIEW_JUSTICES should be taken into account during the nomination process in the game, because once the justice is in office they certainly won't ever consult public opinion ever under any circumstance, as it's the tradition of the court to ignore public opinion and do whatever the justices personally believe the "law" says (and their personal beliefs on this reflect their political ideology, whether it be left-wing or right-wing, authoritarian or anti-authoritarian, etc.).

But since I'm still on vacation and not able to program with this tiny netbook I won't be implementing this feature quite yet. ;D
Title: Re: Modding questions
Post by: SlatersQuest on October 27, 2014, 10:48:14 am
Question: I'm looking in siege.cpp. I am not finding the code that prevents raids when you shut down the relevant base of the attacking faction. Is this code not implemented?
Title: Re: Modding questions
Post by: SlatersQuest on November 09, 2014, 12:28:47 am
Okay, I have a problem.


I've added an additional file to the game, which I use to print out extra stuff. Here's the code in which it is defined, in externs.h:

Code: [Select]
extern FILE *my_new_file;

The compiler gives me the following error message:

Code: [Select]
  "my_new_file", referenced from:
      basesquad(squadst*, long) in crimesquad-commonactions.o
      sleeperize_prompt(Creature&, Creature&, int) in crimesquad-commonactions.o
      mode_title() in crimesquad-titlescreen.o
      review_mode(short) in crimesquad-reviewmode.o
      creatureadvance() in crimesquad-advance.o
      advancecreature(Creature&) in crimesquad-advance.o
      special_bouncer_assess_squad() in crimesquad-mapspecials.o
      ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [crimesquad] Error 1


What am I doing wrong here??
Title: Re: Modding questions
Post by: Reelya on November 09, 2014, 04:21:14 am
If something is defined as extern, that's just a declaration not a definition, is there an actual cpp file where

FILE *my_new_file;

is declared without the extern parameter? This non-extern declaration is actually where the symbol itself is allocated to some chunk of memory. the extern copy is just the way of saying to the compiler "look, my_new_file is a thing, but it's actually created somewhere else, but I'm just telling you about it so you know. I'll tell you where it is when you need it".

Each .o file is created from a .cpp file during the compile stage, but they still contain "unlinked" references. Then in the linker stage, all the unlinked references (like extern stuff) are looked up in each .o file to see what they really point to. If there's no reference ("symbol not found") it means you either didn't create the actual FILE pointer, or didn't compile the cpp file that contains it.
Title: Re: Modding questions
Post by: SlatersQuest on November 09, 2014, 02:26:02 pm
That worked; thank you very much!

I had thought that all of the externs were simply defined there, but I see they're in game.cpp as well. Good to know!