Operational Warfare Developer's Blog

Developer's blog for the Operational Art of War series

About the author

Ralph Trickey maintains TOAW III
I set this Blog up for fun, and for my own edication! Nothing is guaranteed, it's for my own use primarily, so even if I say that something may happen with the next release, please understand that it may not. I plan to post random thoughts and other things like that at random times here. I don't have a specific plan for what will be here.
E-mail me Send mail

Recent posts

Recent comments


The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2017

UI Design and Testing

Sometime I need to sit down and figure out exactly what it would take to convert the dialogs to use CSS-like text files. The code is reasonably close to that now, the difference is that I've got the formattting code next to the display code making for more changes than I'd like for simple items. The interface between the two is the hard part. I'd have to keep a linkage between the variables and the CSS. C# does it handily, for C++ I'd have to write a macro library or something similar to keep global track of variables.

Possibly put a macro section at the top listing all the variables that can be used that the library could use to link to the CSS.

I'm not sure how to deal with the repeating sections like the event view though.


Posted by Ralph Trickey on Monday, August 24, 2015 8:33 PM
Permalink | Comments (0) | Post RSSRSS comment feed


The first rule of finding out where things went south is to make sure that you're looking in the right place :(

I just spent two days looking for where I broke things with a recent change that coudl easily have broken it just to figure out finally that I broke it last year and just hadn't noticed.

I started troubleshooting a big problem, fixed it and didn't go back to figure out where I'd broken the other problem.

I then didn't realize that I had the logging output twice because of a rerganization and spent more time looking at the wrong logs and scratching my head when they didn't match.

Hopefully writing this down will remind me not to do silly things like that.

Posted by Ralph Trickey on Thursday, July 02, 2015 2:49 PM
Permalink | Comments (0) | Post RSSRSS comment feed

UI Code

Here's an example of the new UI code. The old code had a fixed font and used absolute pixel placement so I wrote a quick and dirty UI library based rougly on Deplhi/WPF.
My one real regret is that I didn't reference the CSS manuals when naming the functions instead of relying on my memory of other UI libraries. It would make maintenance simpler.
auto b1 = panel->AddChild(new WideTextButtonComponent(falseCGameUtil::SSCheck(theUnit.name), false))
	->SetSize(-1, eAnchor::leftPositionFreelyPositionFreely);
b1->onClick = [&theUnit](int buttonbool &/*processed*/) {
	if (button == 0) {
	} else {
		GlobalDialogs::PushNextActivePanel(std::shared_ptr<UnitDialogNew>(new UnitDialogNew(*currentUnittrueeStandardButton::STANDARD_BUTTON_OK)));
	return true; };
EDIT:The first line is now auto b1 = panel->AddChild(new WideTextButtonComponent(falseCGameUtil::SSCheck(theUnit.name), false))
It was WideTextButtonComponent *b1 = (WideTextButtonComponent *)panel->AddChild(new WideTextButtonComponent(falseCGameUtil::SSCheck(theUnit.name), false))
	->SetSize(-1, eAnchor::leftPositionFreelyPositionFreely);

Posted by Ralph Trickey on Sunday, May 31, 2015 3:58 PM
Permalink | Comments (1) | Post RSSRSS comment feed


Darn it, why do people insist on creating one entrypoint and passing in 27 different possible parameters.

I just spent 12 hours finding out that I needed to typecast the int to a long long or I'd get memory faults when it tried to read a terabyte of data or some such.


Posted by Ralph Trickey on Friday, May 08, 2015 9:55 PM
Permalink | Comments (0) | Post RSSRSS comment feed

3 steps forward, two steps back.

Well, that was 'fun' After all that work it worked fine on my machine and failed on everyone else's.

So, rewrite everything in libcurl. 

Aside from all the side alleys filled with gangs of thugs, it wasn't too bad.

First there was the calling convention. The 'norm' is cdecl. I was using fastcall. Instead of a reasonable error like 'dude, you've got the wrong calling convention, I got a much more accurate alnd less useful 'function not found.' Once I fixed all those, I got the even more useful "Invalid read from memory '00001'.

Then there was the MFC party. It wasn't a simple, Dude, you need to link the MFC library first, it was 'Duplicate functions'

Good luck googling that one!

Finally I had to toss the cookies. Don't ask me why, but I couldn't just leave the cookies alone, I had read them, remake the exact same cookie, then it was happy.

Anyway, as long as I don't need SSL, I think I can read/write HTML. At least the simple stuff, we'll see about the complicated stuff later.

I'm going to go relax in a Dentists chair now, it should be more fun.


Posted by Ralph Trickey on Tuesday, May 05, 2015 10:38 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Heaps and Heaps

Dang it! Run time libraries shouldn't be lightly intertwined.

I'm trying to link to a C# DLL to do some web related stuff.  Simple right? At least my testbet linked and ran just peachy keen.

Then I tried to link in TOAW.

No peach. Not keen. Errors that have nothing to do with the problem.

After 4 hours, I think I've got it straighted out. You need to include the C++ DLLs when linking to C# instead of just linking them into the program. Why? Darned if I know. Makes no sense to me, but there it is. I may try to separate them later, but for now, it works.


Posted by Ralph Trickey on Tuesday, April 28, 2015 1:24 PM
Permalink | Comments (1) | Post RSSRSS comment feed


Oh how I hate managing PBEM games, it is so much simpler to let the player worry about finding matches and sending the games back and forthCool Simple for a human, not so much for a computer.

So much code, so little progress. I'm hoping to start seeing something visible soon.


Posted by Ralph Trickey on Sunday, April 19, 2015 9:17 AM
Permalink | Comments (1) | Post RSSRSS comment feed


I just had the opportunity to hit two kinds of failure today.

One was the good kind, I tried to generalize sorted lists and after banging my head against different walls for two days decided that Copy/Paste inheritance was the best fit for this :( I could have kept trying to put that square peg into the round hole and it would (might) have worked, but I just wasn't seeing the savings I'd hoped for. So, I backed out 2 days worth of work. I also learned one problem set that C++ inheritance doesn't really work well with. I'd actulaly hit this before but didn't realize that this was the same problem. If you have two trees that are related, you're going to have serious issues trying to keep them related.

One was the bad kind, I spent the next 4 hours doing basically copy/paste inheritance and when done, tried to figure out how to put it back into Git. Before, it gave me warnings about how I might not want to do this and after searching, finding out that I had to check the clean button in order to actually get that earlier version, so... When I double-clicked on the master branch to try to get rid of the detached head (whetever that actually is) this wonderful tool decided that's OK I'll just go ahead and wipe out your 4 hours of work.


Posted by Ralph Trickey on Wednesday, April 01, 2015 9:39 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Unity 5 changes

Unity 5 has made some changes to their product with the 5 release which make it a lot more tempting for me now. The biggest one is that they are now shipping the same engine for the free and paid versions which includes the ability to link to C++ and the free version now includes some important optimizations that weren't there before. I'm going to have to figure out where I can get the time to build a sample in Unreal and Unity to compare them myself. So many toys, so little time.


Posted by Ralph Trickey on Saturday, March 21, 2015 9:56 PM
Permalink | Comments (1) | Post RSSRSS comment feed

Modern C++ code

Just for fun, here's a little of the new code that's being written. Helicopters is an array that is created here and contains only the helicopters and is used instead of looping through the unit array looking for helicopters. This is actually within a loop of all hexes on the map, so it is much faster this way.

Right now, I'm struggling a bit with the class design. Right now, I'm saving/restoring the raw C structs and layering the class library above them. I think that creating the class structure from scratch instead would be cleaner, although I'm not sure that the extra work is worth the gain. One example of where this comes into play would be the Intel class. It's obviously completely separate functionality. One thing I could do with C++ is to put the interface in the UnitMapLocation class and the implementation into a separate CPP file, or even in a #pragma section. Part of me doesn't want to do that since it's going to be difficult to avoid putting things into one huge file. I could leave them there and add forwarding functions, but that might take slightly more time. Even so, that's probalby what I'll end up doing. The release build version should end up optimizing them out, but it's gong to make the debug version slower. Since I normally run the debug version, it impacts me. The release version build takes about 10 minutes.

I've got logical layers to the classes like Terrain, UnitMapLocation, MapGraphics, etc. They are there to help me figure out what the code does. Occasiionally they're a pain, but I think they help.

SpecificUnitList helicopters = SpecificUnitList(0, [](const CUnitType *theUnit) { return theUnit->recceHelicopterIcon() || theUnit->attackHelicopterIcon(); });
if (um.allUnitsInLocationAnyTrue([](const CUnitType &u) {return u.anyLandIcon() && !u.isSeaborneStatus(); })) {
	//TODO:Rework, spotting is only for the topmost unit
	if ((localRecce(xyu.owner()) + helicopterRecce(helicoptersu.owner(), xy)) >= OPRandom::rnd(1, 100))
		spot(xyu.owner(), ueSpotting::STATIC_UNIT_SPOTTING);
		spot(xyu.owner(), ueSpotting::MOVING_UNIT_SPOTTING);
if (um.allUnitsInLocationAnyTrue([](const CUnitType &u) {return u.airUnitSeaInterdicting() || u.getStatus() == AIR_SUPERIORITY_STATUS; }))
	spot(xyu.owner(), ueSpotting::SEA_INTERDICTION_SPOTTING);

Posted by Ralph Trickey on Sunday, March 08, 2015 10:53 AM
Permalink | Comments (1) | Post RSSRSS comment feed