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

Disclaimer

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

© Copyright 2015

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 (0) | 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);
	else
		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

What's worse than a bug that suddenly appears for no apparent reason?

One that suddenly disappears! You can't ignore it even though it's gone, you still have to figure out where it went.

Yesterday, upon the stair,
I met a man who wasn't there.
He wasn't there again today,
I wish, I wish he'd go away...

When I came home last night at three,
The man was waiting there for me
But when I looked around the hall,
I couldn't see him there at all!
Go away, go away, don't you come back any more!
Go away, go away, and please don't slam the door...

Last night I saw upon the stair,
A little man who wasn't there,
He wasn't there again today
Oh, how I wish he'd go away...


Posted by Ralph Trickey on Tuesday, March 03, 2015 1:18 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Button, Button, who's got the button.

Figuring out how big average text is is HARD.

Normal text isn't too bad, there's a function that will take strings in and spit out the size. Trying to set buttons to the same size so they don't look funny isn't nearly as simple when you can vary the font. I've been hip deep in inner leading and other esoterica trying to figure out a scale factor. Inner leading is the lead they used to put at the bottom of a character when compositing text. External leading is on the outside and not part of the character. All this made a lot more sense back when they put physical characters onto a platten and printed that way.

Right now, I'm taking the average character size minus leading (for the height) and comparing that to the current 8 bit/s per character to figure out the button size. It's that or walk through all the strings on buttons at startup and ask what size they are.

I may end up also exposing button width and height overrides in the font.ini file for people to tweak if the want it perfect.

The joys of building things pixel by pixel, most people can just say 'I want a Blue Button Here, with this text and this size.' 

 

 


Posted by Ralph Trickey on Sunday, March 01, 2015 9:17 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Code status

Don't misunderstand me, TOAW was very well written for it's time. I've looked at other programs written around that timeframe and they are absolute messes in comparison. Norm did a fantastic job given the constraints. It was written before C++ so there is a huge reliance on global variables. There is some separation between the logic and display but some parts are better than others. I'm pretty sure it was also written originally as a DOS program and the conversion to Windows works, but it used to have lots of loops polling the input which was the only way to do it in DOS but not the best way in Windows and impractical for mobile. The interface code was written assuming an 800x600 display and everything was coded using pixel coordinates and an 8x8 font. While it wasn't OO, it did do some sensible things like passing x, y as the first two parameters when looking at terrain and other sensible things like that. 

I've got the advantages of both using C++ and OO and having used several windowing systems (Delphi, C#, HTML, and a few others) so I have some ideas on what the programming interface looks like. So I'm taking the time to do an almost complete rewrite of the graphics system to isolate the windows pieces in a couple of source files and writing an abstraction layer above it. 


Posted by Ralph Trickey on Saturday, February 21, 2015 12:51 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Rewiring TOAW dialogs

Right now, it looks like the TOAW dialogs grew a bit organically, they are all very similar, but don't take advantage of inheritance and are complete hand-coded with references to pixel coordinates. While this makes for very pretty, quickly written dialogs and was appropriate back when the resolution was 800x600, it doesn't work very well with today's 4K monitors. It's also very clumsy to modify with separate paths for drawing, mouse move, and mouse click that had to agree. I'm rewriting all of them to be dynamically resized (similar to HTML) depending on the font size instead. The code is a lot simpler, but there are a lot of edge cases to deal with for things like the weather dialog which has a micromap inside of it.

Phase 1 is underway, some of the dialogs are now functional. Once they are all done, phase 2 will be to make them pretty.

Here's a simple example. I'm using C++ and lambdas (inline functions) to handle the actual click

char iString[STRINGLENGTH];

auto *bPrev = buttonPanel->AddChild(new StandardButtonComponent(eStandardButton::STANDARD_BUTTON_PREVIOUSUNIT));

bPrev->SetSize(-1, eAnchor::left, ShrinkToFit, ShrinkToFit)->setOutsideMargins(1, 0)->SetInfo(unitReportControlInfo[0])->SetPrompt(unitReportControlPrompt[0]);

bPrev->onClick = [this](int /*button*/, bool &/*processed*/) {

CUnitType *nextUnit = &invalidUnit;

if (gameMode.isPlaying())

..nextUnit = &CDeploy::nextUnitInOrder(*currentUnit, -1, TRUE);

else

..nextUnit = &CDeploy::nextUnitInOrder(*currentUnit, -1, FALSE);

if (*nextUnit != *currentUnit) {

..if (nextUnit->valid(FALSE)) {

....CDeploy::makeCurrentUnit(*nextUnit, false);//special case - makeNextUnit call is made on exit from dialog.

....auto *dg = new CUnitDialogNew(*currentUnit, true, eStandardButton::STANDARD_BUTTON_PREVIOUSUNIT);

....AddNextActivePanel(std::shared_ptr(dg), true);

..}

}

return true; };

 

 


Posted by Ralph Trickey on Friday, February 20, 2015 9:09 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Software Craftsmanship rant

I posted this elsewhere in response to someone's questions about the synergy between craftsmanship and business needs. I'm copying it here because I can Cool

Sorry, I didn't have time for a shorter rant ;)

First, my understanding of craftsmanship is making a piece of work that is functional and does what the person paying the bills wants. Sometimes it's going to be extremely ornate and sometimes it's going to be very durable. If you make something with lots of frills that the customer didn't ask for, that isn't craftsmanship, that's arrogance.

You didn't say which field you're talking about, I'm gong to assume programming. It sounds a lot like ideas that some programmers would understand, things like software craftsmanship and agile programming. Also some ideas "borrowed" (stolen) from lean manufacturing

What you're talking about is what I'd call overengineering. The most succinct expression I've found is in XP (a branch of Agile Programming) where it's expressed as YAGNI (You Ain't Gonna Need It). 

There shouldn't be any tension between craftsmanship and business need, the business owner is paying the bills. If you can convince the business owner that you can complete the project within the time and budget constraints while using whatever architecture you want, go for it. 

The thing to remember about Craftsmanship is that it's in the eye of the beholder. Your client doesn't care diddly about craftsmanship, he cares whether or not a product ships on time and is complete. Only after those things does he care about maintainability which can be used to sell spending time on 'Craftsmanship.' For a long running project it's easier to sell 'Craftsmanship' if it's used to support his business needs by making it easier to modify as requirements change.

Frankly I'd be careful with the idea of craftsmanship and substitute being proud of the code you wrote but egoless and willing to listen to suggestions or some other meaningless dribble. Craftsmanship is too overloaded a term, and often means that you want to justify using some overcomplicated framework or feel some framework is too complicated and want to write your own.

That doesn't mean that there shouldn't be an architecture, there absolutely should be, but it should start as simple as possible and, trust me, it will become more complicated than it needs to be naturally.

http://en.wikipedia.org/wiki/Lean_manufacturing
http://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
http://programmers.stackexchange.com/questions/110227/writing-robust-code-vs-overengineering


Posted by Ralph Trickey on Friday, February 20, 2015 9:04 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Unreal Engine 4

Great, just what I needed. They dropped the price from 'If you have to ask...' to $19/mo + 5% of the gross.

It is totally C++ and promises to be cross-platform (Windows/Mac/IOS/Android).

Don't get me wrong, it's still very tough to port any program to another platform, or even to do a massive upgrade like that when it wasn't planned from the start, but it might be simpler than Unity, the other platform I was looking at.

Too many toys, not enough time Cry


Posted by Ralph Trickey on Monday, March 24, 2014 6:01 PM
Permalink | Comments (0) | Post RSSRSS comment feed

AI : Hierarchical Plan-Space Planning for Multi-unit Combat Maneuvers.

Game AI Pro has an interesting article (Chapter 13) called 'Hierarchical Plan-Space Planning for Multi-unit Combat Maneuvers.'

I believe it's a modificaiton of a Hierarchical Task Network.

The basic idea is that you create taska and break those into sub tasks and so forth.

The most interesting thing about it for me was that you can then estimate the number of turns it takes each sub-task, roll that up to the main task and use that to decide which way to go. For example, moving to a railhead and boarding the railroad might take less time than travelling by foot.

It doesn't help with deciding whether to attack which flank, etc., but once that's decided, it might be a way to help to muster for the attack, decide that enough forces are gathered and prosecute an assault successfully.

The example they have has a mission, objectives, teams, units, and details on the actions that the units need to do.

Something I want to look into if I get the time.

 


Posted by Ralph Trickey on Tuesday, February 25, 2014 3:04 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Dialog types

I'm thinking that there should be several dialog types.

Single instance would mean that there is one and only one of this specific type, for example unit or formation would have only one.

Modal would be for the combat results and and things like that. It needs to be closed before any other action can be taken.

Multi-instance, I'm not sure which ones will be multi-instance at the moment, I can't think of any where it makes sense. I know some people think that they might want 3 or 4 formations side by side, but I'm not sure it would actually work better in practice than only one.


Posted by Ralph Trickey on Friday, January 31, 2014 1:03 PM
Permalink | Comments (0) | Post RSSRSS comment feed