PDA

View Full Version : [REL] Automated Campaign Editor v0.3


mcoca
05-03-07, 04:46 PM
This is the 0.3 release of the SH Batch Editor, a tool for making automated changes to the campaign files. Please consider it a beta release.

If you want to make some extensive changes to the SH4 campaign, but don't spend hours in the in-game editor, this is your tool. Just enter the values you want to set, and (if needed) the conditions a randomly generated group must fulfill to be modified, run the program, and the entire campaign will have been modified.

The changes to be made are specified as code snippets in the Python programming language (www.python.org) (http://www.python.org%29), but the program has been designed to make it possible to use it with only a minimum of programming knowledge.

At the moment, the program only supports editing random generated groups (including contents and waypoints, so you can add or remove ships from them), but scripted elements, bases, etc, should not be affected in any way by running it. But, just in case, always make backups.

The program is available at:

http://downloads.sourceforge.net/shbatcheditor/shbatcheditor-0.4.zip


It is written in the Java programming language so you will need the Java Virtual Machine (version 1.5 or later), available at http://java.sun.com/ (but likely to be already installed on your computer).

This program is released under the GNU General Public License, and the linked file includes full source code for the technically inclined.

The README.txt file includes all instructions for running simple changes. If you know some programming and want to try more complex changes, in the "samples" folder of the distribution you can find the script to reproduce the changes I'm currently using in my campaign.

Finally, I really don't know how much further I will be able to develop this. That's one of the reasons for releasing it as Free Software, so that everybody who is interested can continue developing it should I no longer have time or (let's face it) interest. If anybody wants to contribute, I sure could use some help.

Hope you enjoy this.

Changes in v 0.4
Added option to run script directly from file.
Added group cloning.
Fixed cargoInt and cargoExt getters. Now it's internalCargo and externalCargo, as per the setters.
Allow logging from scripts.
Added Yanaran's fix to zig-zag code.
Fixed dateline heading and offset bugs.Changes in v0.3:
Added "Output" field to GUI.
Added init.py initialization file.
Added waypoint length and heading read-only attributes.
Changed Waypoint loop attribute to take a Waypoint object.
Added sample zig-zag code to init.py

Egan
05-03-07, 04:49 PM
Very impressive looking. Thanks for this, it looks like it will come in very useful. :up:

ReallyDedPoet
05-03-07, 04:50 PM
Nice effort:up:

RDP

Ducimus
05-03-07, 04:50 PM
Very nice.

mcoca
05-03-07, 04:55 PM
Almost forgot! Please consider this an "undocumented feature" for the moment, but for those who are feeling brave, the distribution includes the entire python standard library, meaning you can do all types of nifty things, including (as per Jace11's suggestion):


from random import randint
group.speed = randint(5,9)
group.updateWaypointSpeed()

Which makes the group speed random between 5 and 9 knots. Obviously, all instances of the group will travel at the same random speed :)

You can use any of the functions described in the python documentation...

(edit to fix problem in example)

Jace11
05-03-07, 05:58 PM
Just re-stating my gratitude for this. It will speed things up for the people who are editing the campaign layers.

akdavis
05-03-07, 06:09 PM
This is superb, especially the random speed functionality.

lurker_hlb3
05-03-07, 06:30 PM
What would be the code to randomly change speed on each way point i.e pt1 is 5, pt 2 is 8 etc ???

mcoca
05-03-07, 06:50 PM
Thank you everybody for your support! Now, start using the thing so I can feel I haven't completely wasted my time :p

What would be the code to randomly change speed on each way point i.e pt1 is 5, pt 2 is 8 etc ???
I'm writing from memory, but it would be something along these lines:


from random import randint
for waypoint in group.waypoints:
waypoint.speed = randint(2,8)
Obviously, change the numbers to the ones you want. The spaces at the beginning of the third line are important, since python uses indentation to control what's inside the loop and what isn't.

BTW, if you want to get cute, there are functions to provide randomness along a probability curve, so most of the time ships will be around the middle of the range, with the occasional fast or slow one. Check the docs if you are interested.

lurker_hlb3
05-03-07, 06:58 PM
Thank you everybody for your support! Now, start using the thing so I can feel I haven't completely wasted my time :p

What would be the code to randomly change speed on each way point i.e pt1 is 5, pt 2 is 8 etc ???
I'm writing from memory, but it would be something along these lines:


from random import randint
for waypoint in group.waypoints:
waypoint.speed = randint(2,8)
Obviously, change the numbers to the ones you want. The spaces at the beginning of the third line are important, since python uses indentation to control what's inside the loop and what isn't.

BTW, if you want to get cute, there are functions to provide randomness along a probability curve, so most of the time ships will be around the middle of the range, with the occasional fast or slow one. Check the docs if you are interested.


It worked perfectly, thanks very much

Yanaran
05-04-07, 09:12 AM
Thanks for this awesome tool. Now I can finally make some changes myself! :)

I have a few simple questions though. I want to reduce traffic similar to your example script, but I also want to make convoys smaller early in the war and have less escorts. Is it enough to just reduce the spawnprobability for every unit in a convoy to say half? Like this for example,

if unit.type == UnitType.DESTROYER:
unit.spawnProbability *= 0.25
else:
unit.spawnProbability *= 0.5

Also, I'd like to remove all gunboats from the subhunter groups, and maybe replace them with some other ships like subchaser or minesweepers. Can I replace the "type" of ship or do I need to remove the gunboat unit altogether and then add a subhunter unit? I want to keep all the stats for the unit the same (crew, spawnprobability etc).

akdavis
05-04-07, 09:44 AM
Best thing to do with gunboats would probably be to change their type so they aren't spawned as patrol vessels (or whatever type is drawn on for that group).

U-Bones
05-04-07, 09:52 AM
It would be nice to have both brown and blue water hunter/killer groups

Blue: DD/Subchaser/Minesweeper
Brown: Subchaser/Minesweeper/Gunboats

or similar.

Brown groups would also be common near smaller ports.

mcoca
05-04-07, 10:15 AM
I have a few simple questions though. I want to reduce traffic similar to your example script, but I also want to make convoys smaller early in the war and have less escorts. Is it enough to just reduce the spawnprobability for every unit in a convoy to say half? Like this for example,

if unit.type == UnitType.DESTROYER:
unit.spawnProbability *= 0.25
else:
unit.spawnProbability *= 0.5
Yes, that should work... except that I'm not sure what happens if the lead unit in the group doesn't spawn? But the editor let's you enter such a group, so it's no big deal.

OTOH, you could remove half the entries using group.units.remove(unit) and some condition, but adding some kind of counter to how many there were and how many you removed.

Also, I'd like to remove all gunboats from the subhunter groups, and maybe replace them with some other ships like subchaser or minesweepers. Can I replace the "type" of ship or do I need to remove the gunboat unit altogether and then add a subhunter unit? I want to keep all the stats for the unit the same (crew, spawnprobability etc).
The best solution, as tater suggested in another thread, would be to move the subhunter and the minesweeper to the "corvette" category by editing the roster files and changing the type=0 to type=1. Then, switch all the patrol craft in the campaign to corvettes:


if unit.type==UnitType.PATROL_CRAFT:
unit.type=UnitType.CORVETTE

And if you want to add some gunboats around coastal areas, do so manually with editor. Unless you are a really enterprising programmer and can figure out a way to tell coastal patrols apart based on long/lat ;)

Yanaran
05-04-07, 11:23 AM
Well that seems a bit more complicated than I thought, what I'm trying right now instead is sort of reverse what you did for destroyers... In every SubHunter group I check if it's a patrol craft and then set that units shipclass to subchaser. I think that should turn all gunboats into subchasers, which is good enough for me until I learn more. :)



if group.groupName.find("SubHunter") != -1:
if group.groupName.find("Jap") != -1:
# less subhunter groups
group.spawnProbability *= 0.5
for unit in group.units:
if unit.type == UnitType.PATROL_CRAFT:
unit.shipClass="SCSubchaser"

mcoca
05-04-07, 04:29 PM
Yanaran, that should work fine, although you will find your subchaser groups a bit boring :D

I would consider adding a few minesweepers into the mix, but changing them to patrol craft in the roster (edit roster\japan\sea\msno13.cfg to set type=0), so they get escort AI. I have done that and so far it's working out well enough.

Otherwise, from my tests, I think task forces should get a drastic reduction. I set them down to 40% of stock, and still managed to find two of them in one patrol.

mcoca
05-04-07, 04:30 PM
BTW, for those who have downloaded and tested the program. Are there any specific features you would like to see in a future version?

akdavis
05-04-07, 04:57 PM
It would be nice to have both brown and blue water hunter/killer groups

Blue: DD/Subchaser/Minesweeper
Brown: Subchaser/Minesweeper/Gunboats

or similar.

Brown groups would also be common near smaller ports.

I believe the devs confused these gunboats with accounts of US sub encountering "converted gunboats." While I can't find an view of a specific wartime Japanese example, here is a US converted gunboat from between the world wars:

http://www.wendymersman.com/rudder/oldrudder/Rudder/Rudderimages/eastland3.jpg

Her upper decks had been removed to increase open water stability. A variety of different ships were converted to gunboat status during the war. Steamships were common.

The gunboats in the game should probably be excised entirely. Both the Atami and the Hira were not part of the Combined Fleet, but rather assigned to the Japanese naval forces in China, as can be seen in this document:

http://www.ibiblio.org/pha/pha/misc/45-41.html

They and their sisters (Atami class: Atami, Futami; Seta class: Seta, Katata, Hira, Hozu) were Yangtze River patrol boats. To show where they where later in the war, references indicate that the Atami was damaged by Chinese aircraft near Tung Ting Lake in China on June 10, 1943, while the Hira was damaged in an air attack at Kiukiang, China.

At the most, they might appear occasionally in Shanghai harbor.

Here are some examples of converted gunboats sunk by US submarines:




SHOSEI MARU
Japanese Navy; 1929; Amagasaki Zosensho; 998 tons; 210 x
30-5x18-7; triple-expansion engines.
The steamship Shosei Maru was taken over by the Japanese Navy
for use as an auxiliary gunboat. On May 20th, 1944, she was torpedoed
and sunk by a U.S. submarine [U.S.S. Silversides] about 50 miles S.W. of
Guam.


NIKKAI MARU
Nissan Kisen K.K.; 1938; Uraga Dock Co.; 2,562 tons; 297-9 x
45x23-8; 201 n.h.p.; compound engines & L.P. turbine. The
steamship Nikkai Maru was taken over by the Japanese Navy and
converted into an auxiliary gunboat. On November 26th, 1943, she
was torpedoed and sunk by the U.S. submarine Ray 350 miles N. of
the Admiralty Islands.


KEIKO MARU
Osaka Shosen K.K.; 1938; Uraga Dock Co.; 2,929 tons;
297 -9x45x23-8; 255 n.h.p.; compound engines & L.P. turbine.
The steamship Keiko Maru was taken over by the Japanese Navy
and converted into an auxiliary gunboat. On November 8th, 1942,
she was torpedoed and sunk by the U.S. submarine Seawolf off
Mindanao Island, Philippines.

Redwine
05-10-07, 06:05 AM
Many thanks ! :up:

mcoca
05-10-07, 06:56 AM
I'm currently working on the next version. Features will include:
Separate entries for input and output folders, so you can run the same changes repeatedly, adjusting them, without having to restore your backups.
A config file where you can put code and definitions for use in your changes. I intend to start this file with some useful functions.
Improvements to the Waypoint API. I think with some small changes it would be possible, for example, to make all convoys zig-zag according to a set plan without having to change each one separately. Right now this is difficult because there is no simple way to insert new WPs.Anyone has a specific request?

FinnN
05-10-07, 07:47 AM
I've not taken a look at this as I'm a .NET user but I think it's a great thing that you're doing here.

Can I make a suggestion in terms of something that would be good, and leave to it you to see if it could be accommodated by your library (assuming it isn't already)?

Basically in a campaign (mission even if you're 'lucky') you can sink the same battleship/cruiser multiple times - fine for destroyers but not so good for
the Yamato. How about a function to search and replace generic ship entries in the campaign file with specific ones? So, someone could then write a little utility that when you run it fills the random battleship entry with a specific one from a database, then it'd fairly easy to only have two Yamato class BBs in the game world. Then when the Yamatos run out, the rest can be filled with a different BB, when they run out it might then be missing altogether from the battlegroup or replaced by a cruiser. If cruisers have all been allocated then a destroyer could be used. Straight away it'd make rare ships rarer, and more of a find when you chance across one. I guess with some research the ships could go into their historical stations/battlegroups in the database when selection occurs.

A second function would then be needed, to look inside a save game file for sunk ships - and then the same routines as above could be run to ensure that you don't bump into it again. This would mean that you don't sink a converted Mogami several times for example, by running the campaign updater between missions. I had a quick look in the save game files and it does seem that ships sunk are in there.

Just a suggestion from someone that's not actually looked at your library so I hope I'm not asking for something already in there. I guess I'm suggesting a search and replace function, something for reading in ship and convoy data from an external source (easy enough to write, but a standard would be good for encouraging people to build on each others work) and something for reading relevant data from a save game file.


Have fun
Finn

tater
05-10-07, 07:56 AM
Wow, the ability to code in zig zags would be amazingly cool. Would it work where you would pick 2 waypoints, then input a degree change off the base course and some interval?

tater

mcoca
05-10-07, 09:04 AM
I've not taken a look at this as I'm a .NET user but I think it's a great thing that you're doing here.
You can take a look at the IKVM (a JVM implemented in .NET) if you still want to play around with it ;) And you can install both Java and .NET without problems, IIRC.


Basically in a campaign (mission even if you're 'lucky') you can sink the same battleship/cruiser multiple times - fine for destroyers but not so good for
the Yamato. How about a function to search and replace generic ship entries in the campaign file with specific ones?

Can be done already, but on what would you base what specific type to use for each case? The whole task force business needs a real overhaul anyway. Less movements of entire fleets and more small forces redeploying to/from home ports to advance bases, for example.

So, someone could then write a little utility that when you run it fills the random battleship entry with a specific one from a database, then it'd fairly easy to only have two Yamato class BBs in the game world. Then when the Yamatos run out, the rest can be filled with a different BB, when they run out it might then be missing altogether from the battlegroup or replaced by a cruiser. If cruisers have all been allocated then a destroyer could be used. Straight away it'd make rare ships rarer, and more of a find when you chance across one. I guess with some research the ships could go into their historical stations/battlegroups in the database when selection occurs.

I think some people are already working on this. I agree with the basics, but I think scripting 100% accurate historical data could be a mistake, since in the end it takes away the mystery of what you will find. Adding some fuzzyness to the data would be very good.

For example, according to combinedfleet.com, the Yamato left Truk for Japan on May 8th 1943. In Japan it was drydocked for maintenance and didn't leave until August 17th. Armed with those facts, a player could easily ambush the Yamato in every career. I think random groups should be used to make the BB leave at some point in May and come back at some in August, for example.


A second function would then be needed, to look inside a save game file for sunk ships - and then the same routines as above could be run to ensure that you don't bump into it again. This would mean that you don't sink a converted Mogami several times for example, by running the campaign updater between missions. I had a quick look in the save game files and it does seem that ships sunk are in there.

Sounds very interesting and certainly doable. It would something to integrate in a SH3 Commander kind of program. Any volunteers to implement it? :D The save game format is very similar to the mission format (Windows INI files, both of them), so it's easy to parse it.

Not something I plan to do, but if someone gives it a try, I'll be happy to help.

mcoca
05-10-07, 09:11 AM
Wow, the ability to code in zig zags would be amazingly cool. Would it work where you would pick 2 waypoints, then input a degree change off the base course and some interval?
We can only do that by inserting new waypoints. My idea would be to automate the generation of those waypoints. For example, to replace a waypoint with a zigzag course alternating 30 degrees off the base course at intervals of 10nm, you could do something like:
waypoint.zigzagTo(30,10) The problem I see with that method is that it conflicts with random waypoints, so every instance of the group would follow essentially the same (zigzagging) route. Really, this should be implemented by the devs, not hacked in by us.

mcoca
05-13-07, 04:14 AM
I just made a new release. Aside from the new "output" field, which allows you to select a destination for the changed files, so not to overwrite the originals, the most useful change is the support for zigzagging via new waypoints.

There is sample zigzagging code in the README. If anyone knows how to make that a bit cleaner, I would love to see it. In any case, zigzagging as currently implemented will cause odd behaviour when it interacts with random waypoints, so check your changes.

Enjoy!

terrapin
05-13-07, 04:39 AM
I just made a new release. Aside from the new "output" field, which allows you to select a destination for the changed files, so not to overwrite the originals, the most useful change is the support for zigzagging via new waypoints.

There is sample zigzagging code in the README. If anyone knows how to make that a bit cleaner, I would love to see it. In any case, zigzagging as currently implemented will cause odd behaviour when it interacts with random waypoints, so check your changes.

Enjoy!

Is this the actual new release you're talking about?
http://mpgtext.net/pics/sh4batchedit.jpg

mcoca
05-13-07, 04:43 AM
Is this the actual new release you're talking about?

Yep. I had edited the first post with the correct URL, changes, etc. I guess I should have made it clear in my post :) Sorry about that.

terrapin
05-13-07, 04:45 AM
Is this the actual new release you're talking about?
Yep. I had edited the first post with the correct URL, changes, etc. I guess I should have made it clear in my post :) Sorry about that.

Thank you!

Yanaran
05-13-07, 06:38 AM
I'm having problems removing units from groups. Specifically I want to remove all tankers from task forces (so I can speed them up)


if group.groupName.find("TaskForce") != -1:
for unit in group.units:
if unit.type == UnitType.TANKER:
group.units.remove(unit)



I get an error that says:
Traceback (innermost last)
File "<string>", line 2, in ?

Any ideas?

mcoca
05-13-07, 06:51 AM
I'm having problems removing units from groups. Specifically I want to remove all tankers from task forces (so I can speed them up)

I get an error that says:
Traceback (innermost last)
File "<string>", line 2, in ?

Any ideas?
Does it say something about a ConcurrentModificationException too? That's what I get if I try your code.

The problem is removing items from the middle of a list while you are iterating over it. It's a very common problem, and IMO Java doesn't fix it too well. You can work around it like this:


if group.groupName.find("TaskForce") != -1:
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.TANKER:
i.remove ()


I'll try to find a better syntax for the next release...

Yanaran
05-13-07, 06:56 AM
Yes, concurrentyadayada that's it :)

Your workaround seems to work, I was trying to figure it out using the iterator but didn't think to try i.remove() hehe.

mcoca
05-13-07, 06:59 AM
Yes, concurrentyadayada that's it :)

Your workaround seems to work, I was trying to figure it out using the iterator but didn't think to try i.remove() hehe.
I had the same problem inserting the zigzagging waypoints, that's why I knew the solution :D You should see the hack I had to do to insert a waypoint before the current one (actually, it's in init.py)...

Yanaran
05-13-07, 08:19 AM
I have a suggestion for the zigzagging.

I've tried a few zigzags on the convoy files and checked the results in the mission editor. I notice that there are often problems with the final zig, especially if the waypoint at the end is near land. What happens is that if the last zig is almost as long as the distance to the "end waypoint", you'll end up almost at a 90 degree angle to the final waypoint and if it's close to shore odds are you'll end up with a waypoint that's on land. For example try the example from the readme on the 41a_jap_convoys and look at the waypoints just outside Manila.

So my suggestion would be that instead of creating zigzags all the way to the waypoint, stop zigging one step earlier so the last leg will be between 1 and 2 "distance" instead of between 0 and 1.

I *think* this change to init.py will fix it:

In zigZagToWaypoint(waypoint,iterator,offset,distance ) change

for x in range(0,zigSteps(waypoint, offset, distance)): to
for x in range(0,zigSteps(waypoint, offset, distance)-1):
I've tried it and it looked better on the manila waypoint I talked about above, but I'm no expert in python so I don't know if it breaks something else. :)

mcoca
05-13-07, 08:54 AM
I've tried a few zigzags on the convoy files and checked the results in the mission editor. I notice that there are often problems with the final zig, especially if the waypoint at the end is near land. What happens is that if the last zig is almost as long as the distance to the "end waypoint", you'll end up almost at a 90 degree angle to the final waypoint and if it's close to shore odds are you'll end up with a waypoint that's on land. For example try the example from the readme on the 41a_jap_convoys and look at the waypoints just outside Manila.
You are right, it looks bad. Automated changes can do a lot, but they are not magic (yet :D), so that's why you should always check the resulting file.


So my suggestion would be that instead of creating zigzags all the way to the waypoint, stop zigging one step earlier so the last leg will be between 1 and 2 "distance" instead of between 0 and 1.

That fixes the last zig-zag What about the first? The same problem applies... maybe the long term solution would be to include a "safety zone" around the end points of the zig-zag.


In zigZagToWaypoint(waypoint,iterator,offset,distance ) change

for x in range(0,zigSteps(waypoint, offset, distance)): to
for x in range(0,zigSteps(waypoint, offset, distance)-1):
I've tried it and it looked better on the manila waypoint I talked about above, but I'm no expert in python so I don't know if it breaks something else. :)
That works, and I'll include it in the next release, unless we comeup with a better solution for the beginning of the zig-zag.

Thanks!

Yanaran
05-13-07, 05:06 PM
Well, let me know if you figure out how to get zig-zags to play nice with random waypoints. ;)

I can't decide if I want to keep the random waypoints or have all convoys follow a precise path but doing zig-zags. As much as I want the convoys to zig-zag I don't want them to pass the exact same spots over and over again, I just know I'd end up "cheating". :D

tater
05-13-07, 05:22 PM
There is anoother way to create "random" zig zag paths.

Use the loop functionality. There is a FAQ about making alternat paths with it. Have waypoints 2 to X be zig zag along a path. Have waypoint X+2 start next to waypoint 2 itself. Waypoints X+2 to Y are a zig zag on an alternate path. Have waypoint X+1 have a 100% loop to waypoint Y.

You now have 2 alternating zig zag paths. Set the % chance of this convoy at 10% of what you want to see.

Take this convoy or merchant group, then perhaps the program could be used to clone it, with every single waypoint offset a few kilometers in one direction. Make 10 such clones. You now have a cloud of alternating zigzags each with a 10% chance of happening, but you have 10 of them. Offset the start times, etc to minimize the chances of 2+ at once.

That might work, anyway.

Alternatly, you could make a cloud of such alternating paths within the same group. Just set a bunch of waypoints before the first zigzag to give many chances of alternate paths that are side by side within a few km.

mcoca
05-13-07, 06:18 PM
I agree, it's a tough decision between zigzags and random routes. Looping will work, but in its current incarnation the zigzagging code doesn't really support loops. They will be maintained, but the ships will not zigzag along the alternative route.

This is one of those frustrating problems: we can spend months finding a kludge that almost works, but makes the campaign files ten times bigger. But the devs can probably code zigzagging into the AI in a few hours at most.

Today I discovered http://dangerdeep.sourceforge.net/ an open source subsim in the early phases of development (it already looks pretty, though). I really hope they get it working... the things we could do with it.

Yanaran
05-13-07, 06:57 PM
Well I just finished my first patrol with all convoy routes replaced with zigzagging waypoints (I set all waypoint.radius = 0) and I loved it. For the first time in weeks I missed an entire spread when I fired precisely at the "wrong" moment from about 7000yards out (mk16 torps). :rock:

The convoy turned 40 degrees to port when the torpedoes where about 1/3 on their way and they all missed by what felt like miles. It might be easier to find convoys like this, but it's definatly harder to get the kills. I don't know what would be realistic settings for the zig-zags but I used 20degrees and 10miles like your example script.

tater
05-13-07, 09:57 PM
mcoca,

What about the ability to cut and paste after a fashion? Not just the unit, but a group of waypoints?

I might make a screenshot to show you what I mean.

tater

tater
05-13-07, 11:53 PM
Is it possible to make it apply the zig-zags only between certain pairs of waypoints for a group?

I make a convoy sail from Tokyo Bay to Truk. I make a series of waypoints to get them to the open ocean, say 6. Waypoint 7 is near Truk.

I then make waypoint 8 all the way back next to 6. 9 is next to Truk, but offset from 7. 10 is back near 6/8. 11 near Truk, etc.

I'd have the campaign editor then make zi-zags only between waypoints 6-7, 8-9, 10-11, 12-13, 14-15. I now have 5 zig-zags from near Tokyo to near Truk. I could do 20 if I wanted 5km apart and I'd have a 100km swath.

I'd set all of the "near Truk" waypoints (numbers would change since you'd add the zig-zags between) to 100% loop to the very last waypoint for the group, AT Truk. Some of the very first open ocean waypoints would then have a loop % to one of the alternate routes.

I tested this, and it works, I can add as many alternate routes for 1 group as I like. If a program could do the zig-zags between waypoint pairs of my choosing it's make it really easy.

I agree that it would be better if the devs just coded the game correctly instead though.

mcoca
05-14-07, 03:13 AM
tater,

About copy/paste, do you mean copying the entire route from one group to another? Yes, it's possible, with limitations: you cannot alter the routes after copying in the same run of the program, and you cannot insert just some waypoints. This can be fixed in new versions, though. I can show you code if you tell me exactly what you want.

I see what you mean with loops. You can zigzag some waypoints and no others, but you need to "tag" the zigzagging ones in some way. I suggest giving them a random radius, then removing it in the same change, like this:


i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.radius > 0
waypoint.radius = 0
zigZagToWaypoint(waypoint,i,20,10)

You could even choose what zigzag you want by setting the radius to a given value. For example, this will make a radius of 10.20 to be interpreted as "zigzag ten miles, offset 20 degrees" (untested, so be careful about it):


i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.radius > 0
# extract distance & convert to meters
distance=int(waypoint.radius)*1852
angle=(waypoint.radius-int(waypoint.radius))*100
zigZagToWaypoint(waypoint,i,angle,distance)
waypoint.radius = 0

Yanaran
05-14-07, 06:14 AM
Is it possible to make it apply the zig-zags only between certain pairs of waypoints for a group? Maybe I misunderstand what you want to do, but from your description it sounds like the suggestion in the readme with a distance check would work? Make the distance check extra long to make sure you only get it on the 6-7, 7-8 etc legs.

for 500nm:
if waypoint.length > 500*1852:
zigZagToWaypoint(waypoint,i,20,10)
I used 100nm when I tried on the stock convoy files, but 500 should ensure you only get it on very long waypoints.

tater
05-14-07, 08:36 AM
^cool. that should do. i will make an example to show you exatly what i mean. The goal might be to automate the process somehow.

tater
05-14-07, 11:07 AM
OK, I'm semi-clueless here.

I have a mission to test. I have it set under Input.

Under Group conditions I have:

i = group.waypoints.iterator ()
for waypoint in i:
# 400 * 1852 is 400 NM in meters.
if waypoint.length > 400*1852:
zigZagToWaypoint(waypoint,i,20,4.5)

It gives a syntax error (I just copied the example in the readme and altered the numbers a little).

mcoca
05-14-07, 11:16 AM
Under Group conditions I have:

i = group.waypoints.iterator ()
for waypoint in i:
# 400 * 1852 is 400 NM in meters.
if waypoint.length > 400*1852:
zigZagToWaypoint(waypoint,i,20,4.5)

It gives a syntax error (I just copied the example in the readme and altered the numbers a little).
It needs to be in group change. Group condition is to filter the groups (saving you an 'if' statement), and must be either empty or a true/false statement :)

Also, I'm guessing it's because you didn't put code tags around the example, but just in case, spacing matters in python, so make sure what's inside the if and for statments is indented beyond them.

tater
05-14-07, 11:43 AM
OK, I got it. Tabbing was off.

Yanaran
05-14-07, 11:53 AM
Exactly like you wrote it but with proper spacing in front


i = group.waypoints.iterator ()
for waypoint in i:
# 400 * 1852 is 400 NM in meters.
if waypoint.length > 400*1852:
zigZagToWaypoint(waypoint,i,20,4.5)

Then just paste that in group change, rather than group condition (you can leave that empty).

Edit: Also just a suggestion from playing a patrol with zig-zagging convoys: 4.5nm might be too short, the AI isn't very good at turning in formation. :)

tater
05-14-07, 11:54 AM
BTW, this tool is an amazing addition to the toolbox. Thank you so much.

tater
05-14-07, 11:57 AM
http://www.mediafire.com/?8jzux3g1gxb

that is the mission file I made (quick mission).

Open it with the editor and take a look!

mcoca
05-14-07, 12:37 PM
tater,

Good work! Are you using Yanaran's fix in init.py? Some of your waypoints come out of zigzag at extreme angles, which will break the AI formations.

BTW, for everyone playing with zigzags, I recommend you use the output path option in the program, so your original file is untouched. That way you can always edit without zigzags and add them later. Once all those waypoints are put into place, it looks very confusing.

mcoca
05-14-07, 12:41 PM
Edit: Also just a suggestion from playing a patrol with zig-zagging convoys: 4.5nm might be too short, the AI isn't very good at turning in formation. :)

Now, that's an understatement. It's even worse with scripted formations, BTW. As I mentioned in another thread, I ambushed the Japanese fleet going to Leyte Gulf and sank the Yamato. After the turning and confusion, they decided to reform... in a standard, compact, convoy box of cruisers and battleships! There was no way to launch a torpedo into that formation and not hit something.

tater
05-14-07, 12:47 PM
Ah, no, I didn't use the changes Yanaran made. I misunderstood and thought that you had added those changes to version 0.3.

The 4.5nm was based on the base speed of 9 knots. That was for a zig or zag every 30 minutes.

Later in the war every 5 minutes was not uncommon. 9-10nm for that convoy would mean only 1 change per hour, which is better than default, but pretty unlikely to spoil a torpedo attack. A long torpedo run might be 4 minutes, unless there is a significant chance of a course change during a long run like that, it will have little effect.

tater
05-14-07, 12:50 PM
Edit: Also just a suggestion from playing a patrol with zig-zagging convoys: 4.5nm might be too short, the AI isn't very good at turning in formation. :)
Now, that's an understatement. It's even worse with scripted formations, BTW. As I mentioned in another thread, I ambushed the Japanese fleet going to Leyte Gulf and sank the Yamato. After the turning and confusion, they decided to reform... in a standard, compact, convoy box of cruisers and battleships! There was no way to launch a torpedo into that formation and not hit something.

This shows where the people coding the actual AI need to either learn something of IJN doctrine, or ASK PEOPLE WHO MIGHT. It's like the CV formations. Standard practice was a 7km spacing between CVs in the IJN. 7,000m between ships in a box formation. So of the escorting ships were out on the flanks 15km in a shallow arrow shape.

I'd think that SOP for large surface combatants should probably be line astern, even though that was a combat formation and not a general steaming formation.

mcoca
05-14-07, 01:08 PM
This shows where the people coding the actual AI need to either learn something of IJN doctrine, or ASK PEOPLE WHO MIGHT. It's like the CV formations. Standard practice was a 7km spacing between CVs in the IJN. 7,000m between ships in a box formation. So of the escorting ships were out on the flanks 15km in a shallow arrow shape.

I think that's a symptom of two things: programming good AI is very hard, and it does very little to sell games. For example, I played around with writing a simple formation keeping AI a few months ago, and it was surprisingly difficult. In this case, it obviously felt like I had upset the formation so much they had to reform in some way, and they defaulted back to the box formation.

I'd think that SOP for large surface combatants should probably be line astern, even though that was a combat formation and not a general steaming formation.
Actually, in that particular case, the correct formation would have been a sparse box, wouldn't it? The book I have on Leyte Gulf doesn't list distances, but it shows a kind of box with the heavy columns interspersed with destroyer columns.

tater
05-14-07, 01:31 PM
Possibly, combat vs regular steaming formations varied wildly. Once engaged, standard practice for surface combatants would be to assume a line formation to concentrate fire. A box masks some of the ships farther from the enemy.

Varied a lot though.

AI is indeed really tricky. It would be nice to have the waypoints include a "zig-zag" toggle with degrees and time interval though.

I don't expect it to happen, though, which is why this tool you have created is so great.

Re: Copy and Past:
For copy and paste there are 2 features I'd like to see.

1. copy a group, waypoints and all, and paste a copy of it offset enough that they are unlikely to overlap---tot he opposite side of the globe if needed. Then in the editor you lasso it and drag it where you want.

2. the ability to select a group of waypoints (same as for the zig-zag, for example) and paste them with an offset set by the user. The waypoints should be added to the END of the group's waypoints. So if the group has 20 waypoints, I could select waypoints 6-13 and paste them 10nm West. There would then be a long waypoint connecting waypoint 20, and the new waypoint 21 (which is just #6 moved west 10nm).

tater

tater
05-14-07, 02:04 PM
That was a Q&D test, but this shows great promise. Ideally, I would use some of your other suggestions for "tagging" waypoints with odd radius values. Such a recurring, random convoy would (ideally) have maybe 10 alternate paths, where some even overlap. The tagged waypoints would get different zig-zags as well. Some get a 20 degree aver 30 minutes, so every hour, others get a 30 degree, and so forth. This would be particularly effective for the random singleton (with the odd 2d ship) Merchant layers. Formation keeping would be no problem, and they could even have some very aggressive zig zagging, like every 2-5 minutes (gotta figure a lone merchant ship is gonna have to be aggressive to survive).

mcoca
05-14-07, 02:10 PM
I understand the copy&paste ideas now. They seem easy, so I'll add them for the next version. That will have to wait at least a few days, though, since I'll be out of town tomorrow.

tater
05-14-07, 03:04 PM
Right now, I have a notepad document with the code I am using in there so I can cut and past it into the appropriate fields. Is this what I should expect, or am I missing something? No problem if that is the easiest way. If it is, then perhaps a library of useful (remarked) examples would be in order as a txt doc?

That way some of the code-impared (myself, last code I ever wrote was FORTRAN back in the 80s) can have stuff to plug in where all they need to do is change numbers.

I might not be able to use particularly esoteric elements of this program, but I plan on beating the livig hell out of it.

:up:

tater

mcoca
05-14-07, 03:35 PM
There are quite a few small examples in the README. Also, you can define new functions for future use by adding them to the init.py file (see the file for a few examples).

Other than that, yes, copy/paste is the best way. I wanted something simple for the non-programmer and that wasn't too hard for me to code. If there is enough interest, I can add a second interface where you can just run code directly from a file.

lurker_hlb3
05-16-07, 06:36 PM
I've found a "bug" when generating "zigzag's" that cross 180 longitude, it will generate positions that go around the world vice crossing the dateline correctly

mcoca
05-17-07, 06:25 AM
I've found a "bug" when generating "zigzag's" that cross 180 longitude, it will generate positions that go around the world vice crossing the dateline correctly

Yes, that makes sense (I actually sort of considered it would happen, but didn't think it serious). I'll check where the boundary is (in coordinates) and add the appropiate safeguards for 0.4.

Thanks,

lurker_hlb3
05-18-07, 03:27 PM
having a problem with "cargoExt & cargoInt". When I use/change them get "error" saying that these item are read only. Was using them in contection with editing / creating merchants.


also


is there code to "randomly" selecting "crewratings" ?

tater
05-18-07, 03:59 PM
^^^ wow, that would be an amazing set of functionality. The ability to pick a number of objects (which it does now) then repopulate some fields with values from a list of possible values randomly.

You can do this after a fashion now by having a few ships of the same type with a % chance of appearing, each with a different crew rating, the only problem being you might very well see ALL of them at once. Sometimes you might want only 1 ship, but of variable skill (or internal/external cargo, etc)

lurker_hlb3
05-18-07, 04:07 PM
Here some test code that I'm working on, it's for Japanese Convoys ( 41a / 42a /42b /43a / 44a / 44b.

I've play test this and some other code for Merchants / TF / SubHunters, and let be the one to tell you, "patrols" are no longer boring



if group.groupName.find("Convoy") != -1:
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.CARGO:
i.remove ()
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.TANKER:
i.remove ()
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.DESTROYER:
i.remove ()
if group.groupName.find("Convoy") != -1:
if group.groupName.find("Jap") != -1:
if group.gameEntryDate.after(Mission.date("19411101")) and group.gameEntryDate.before(Mission.date("19420831")):
#merchant 1
mer=RndUnit.createCargo("Japan", 100)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 2
from random import randint
padd= randint(65,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 3
from random import randint
padd= randint(45,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 4
from random import randint
padd= randint(35,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#tanker 1
from random import randint
padd= randint(80,100)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
if group.groupName.find("Convoy") != -1:
if group.groupName.find("Jap") != -1:
if group.gameEntryDate.after(Mission.date("19420831")) and group.gameEntryDate.before(Mission.date("19430831")):
#merchant 1
mer=RndUnit.createCargo("Japan", 100)
mer.number=2
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 2
from random import randint
padd= randint(65,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 3
from random import randint
padd= randint(45,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 4
from random import randint
padd= randint(35,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#tanker 1
from random import randint
padd= randint(80,100)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#tanker 2
from random import randint
padd= randint(35,65)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#escorts
from random import randint
padd= randint(75,85)
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, padd)
escort.configurationDate=group.gameEntryDate
group.units.add(escort)
if group.groupName.find("Convoy") != -1:
if group.groupName.find("Jap") != -1:
if group.gameEntryDate.after(Mission.date("19430831")) and group.gameEntryDate.before(Mission.date("19440531")):
#merchant 1
mer=RndUnit.createCargo("Japan", 100)
mer.number=2
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 2
from random import randint
padd= randint(65,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 3
from random import randint
padd= randint(45,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 4
from random import randint
padd= randint(35,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#tanker 1
from random import randint
padd= randint(80,100)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#tanker 2
from random import randint
padd= randint(35,65)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#escorts
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, 100)
escort.configurationDate=group.gameEntryDate
escort.crewRating = CrewRating.VETERAN
group.units.add(escort)
from random import randint
padd= randint(75,85)
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, padd)
escort.number=1
escort.configurationDate=group.gameEntryDate
escort.crewRating = CrewRating.VETERAN
group.units.add(escort)
from random import randint
padd= randint(45,85)
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, padd)
escort.configurationDate=group.gameEntryDate
escort.crewRating = CrewRating.ELITE
group.units.add(escort)
if group.groupName.find("Convoy") != -1:
if group.groupName.find("Jap") != -1:
if group.gameEntryDate.after(Mission.date("19440530")) and group.gameEntryDate.before(Mission.date("19450831")):
#merchant 1
mer=RndUnit.createCargo("Japan", 100)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 2
from random import randint
padd= randint(65,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 3
from random import randint
padd= randint(45,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#merchant 4
from random import randint
padd= randint(35,85)
mer=RndUnit.createCargo("Japan", padd)
mer.configurationDate=group.gameEntryDate
group.units.add(mer)
#tanker 1
from random import randint
padd= randint(80,100)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#tanker 2
from random import randint
padd= randint(35,65)
tkr=RndUnit.createTanker("Japan", padd)
tkr.configurationDate=group.gameEntryDate
group.units.add(tkr)
#escorts
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, 100)
escort.configurationDate=group.gameEntryDate
escort.crewRating = CrewRating.VETERAN
group.units.add(escort)
from random import randint
padd= randint(75,85)
escort=RndUnit.createWarship("Japan", UnitType.DESTROYER, True, padd)
escort.crewRating = CrewRating.VETERAN
escort.configurationDate=group.gameEntryDate
group.units.add(escort)


if group.columns > 1:
group.columns = 2

if group.spacing > 1:
from random import randint
group.spacing = randint(500,995)

if group.groupName.find("Convoy") != -1:
if group.groupName.find("Jap") != -1:
if group.gameEntryDate.before(Mission.date("19421231")):
from random import randint
group.spawnProbability = randint(25,45)
elif group.gameEntryDate.before(Mission.date("19431231")):
from random import randint
group.spawnProbability = randint(35,85)
elif group.gameEntryDate.before(Mission.date("19441231")):
from random import randint
group.spawnProbability = randint(45,90)
else:
from random import randint
group.spawnProbability = randint(35,50)



if group.repeatIntervalMinutes > 1:
from random import randint
group.repeatIntervalMinutes = randint(3000,10000)


if group.autoReportProbability > 1:
from random import randint
group.autoReportProbability = randint(5,25)

if group.autoReportInterval > 1:
from random import randint
group.autoReportInterval = randint(1440,9999)

if group.columns > 1:
group.columns = 2

if group.spacing > 1:
from random import randint
group.spacing = randint(500,995)

i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.loopProbability > 0:
from random import randint
waypoint.loopProbability = randint(2,8)

i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.radius > 0:
waypoint.radius = 0

i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.length > 500*1852:
zigZagToWaypoint(waypoint,i,0,100)

i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.length > 99*1852:
from random import randint
angle= randint(15,35)
distance= randint(12,50)
zigZagToWaypoint(waypoint,i,angle,distance)

from random import randint
for waypoint in group.waypoints:
waypoint.speed = randint(7,12)

mcoca
05-18-07, 04:42 PM
having a problem with "cargoExt & cargoInt". When I use/change them get "error" saying that these item are read only. Was using them in contection with editing / creating merchants.
I expanded the internal names to "internalCargo" and "externalCargo". I have no idea why the error is so silly...

is there code to "randomly" selecting "crewratings" ?
Not per se, but it's really easy to create your own:


unit.crewRating=choice((CrewRating.POOR, CrewRating.NOVICE, CrewRating.COMPETENT))

That will select a random element from that list. Add or remove elements at will. You can also edit init.py to add a function that does that as shorthand.

tater
05-18-07, 04:44 PM
Damn.

I wish I knew half of what that was doing, looks pretty interesting, though.

mcoca
05-18-07, 04:47 PM
Here some test code that I'm working on, it's for Japanese Convoys ( 41a / 42a /42b /43a / 44a / 44b.

I've play test this and some other code for Merchants / TF / SubHunters, and let be the one to tell you, "patrols" are no longer boring.

Wow, those are pretty extensive changes. I have created a monster! ;)

Seeing the kind of things people are doing, next version will definitely have a "run script from file" option. Let's see if I have time to put it together tomorrow.

lurker_hlb3
05-18-07, 06:13 PM
mcoca

Thanks for the info :up:

tater
05-18-07, 06:20 PM
I don't suppose you could remark that code for a slacker like me to try and figure out exactly what's going on. I can see much of it, but that one huge sample marked up would be an invaluable learning tool.

<S>

tater

Yanaran
05-18-07, 06:49 PM
I don't suppose you could remark that code for a slacker like me to try and figure out exactly what's going on. I can see much of it, but that one huge sample marked up would be an invaluable learning tool.

<S>

tater It's not as complicated as it might look. Most of the size is because he's got a separate if statement for every thing he wants to change, no doubt because he started out doing one change and testing, then adding another change and testing, etc.

First he clears out all convoys of ships, then adds them back depending on the date. Few ships and no escorts in the beginning, then more ships and more escorts as the war progresses.

After that he changes the shape of the convoys by randomizing the separation between ships and limiting the number of columns. He also reduces and randomizes the spawn probability of each convoy to what I think most would consider more realistic chances (less in the beginning, then more, and in the end less again). Then he lowers and randomizes report probability, randomizes "respawn interval" and "report interval".

Then he changes the convoys shape again to the same as he changed above. :p (probably accidental copy/paste hehe)

At the end he's creating zig-zags by removing the radius of "random waypoints" and splitting them up in 500nm segments. You have to remove radius on waypoints for zigzags to work right or ships will travel very strange paths. :) Each segment is then turned into a random zig-zag pattern and finally the speed on each waypoint is randomized.

lurker_hlb3
05-18-07, 07:03 PM
I don't suppose you could remark that code for a slacker like me to try and figure out exactly what's going on. I can see much of it, but that one huge sample marked up would be an invaluable learning tool.

<S>

tater It's not as complicated as it might look. Most of the size is because he's got a separate if statement for every thing he wants to change, no doubt because he started out doing one change and testing, then adding another change and testing, etc.

First he clears out all convoys of ships, then adds them back depending on the date. Few ships and no escorts in the beginning, then more ships and more escorts as the war progresses.

After that he changes the shape of the convoys by randomizing the separation between ships and limiting the number of columns. He also reduces and randomizes the spawn probability of each convoy to what I think most would consider more realistic chances (less in the beginning, then more, and in the end less again). Then he lowers and randomizes report probability, randomizes "respawn interval" and "report interval".

Then he changes the convoys shape again to the same as he changed above. :p (probably accidental copy/paste hehe)

At the end he's creating zig-zags by removing the radius of "random waypoints" and splitting them up in 500nm segments. You have to remove radius on waypoints for zigzags to work right or ships will travel very strange paths. :) Each segment is then turned into a random zig-zag pattern and finally the speed on each waypoint is randomized.

:up: right on the mark Yanaran, this code is in a "beta" work stage. After I fine tune it I'll add comments for each section of code.

tater
05-18-07, 09:28 PM
I've been experimenting with a plan towards more accurate (historically) layers. This is very cool indeed.

tater

lurker_hlb3
05-18-07, 10:38 PM
I've been experimenting with a plan towards more accurate (historically) layers. This is very cool indeed.

tater

I hear you. Reviewing all the different layer for the Japanese and you can see it just the same old thing over and over. after playing them for a while, you know excatly what speed their traveling and their not going the maneuver, "BORING" :down:

During some of my play testing with the code I posted early, you have to stay on your toes "all" the time. The conveys will maneuver when you least expect it and you "will" have to recompute your setup. :up:

Have been do some research to attempt to create layer that will be as close to real world as possible within the confines of SH4

Yanaran
05-19-07, 07:04 AM
I hear you. Reviewing all the different layer for the Japanese and you can see it just the same old thing over and over. after playing them for a while, you know excatly what speed their traveling and their not going the maneuver, "BORING" :down:
If I can just make one suggestion, it would be that you don't need to go overboard with the random numbers everywhere. :D

For instance when you recreate your convoys, there's no need to randomize the "padd" number that represents spawn probability for the ship created. If you create 4 ships all with random spawn probability, you'll still get 0-4 ships in the convoy just as if you created them with set probabilities of say, 80 60 40 20% each. You won't be able to tell the difference between a convoy created with those settings and one created with, say, 75 36 54 49% that you might get from your random probabilities. Just a suggestion to shorten down your code hehe.

Also about randomizing speed on the waypoints, I highly recommend doing it after you've split up the paths in 100nm segments and before creating zigzags. The reason beaing that the game is already poor at maintaining formation in zig-zag turns and if you alter speed in the turns it gets even worse. It would look something like this


from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.loopProbability > 0:
waypoint.loopProbability = randint(2,8)
if waypoint.radius > 0:
waypoint.radius = 0
if waypoint.length > 500*1852:
zigZagToWaypoint(waypoint,i,0,100)
for waypoint in i:
waypoint.speed = randint(7,12)
if waypoint.length > 99*1852:
angle= randint(15,35)
distance= randint(12,50)
zigZagToWaypoint(waypoint,i,angle,distance)

lurker_hlb3
05-19-07, 08:25 AM
I hear you. Reviewing all the different layer for the Japanese and you can see it just the same old thing over and over. after playing them for a while, you know excatly what speed their traveling and their not going the maneuver, "BORING" :down:
If I can just make one suggestion, it would be that you don't need to go overboard with the random numbers everywhere. :D

For instance when you recreate your convoys, there's no need to randomize the "padd" number that represents spawn probability for the ship created. If you create 4 ships all with random spawn probability, you'll still get 0-4 ships in the convoy just as if you created them with set probabilities of say, 80 60 40 20% each. You won't be able to tell the difference between a convoy created with those settings and one created with, say, 75 36 54 49% that you might get from your random probabilities. Just a suggestion to shorten down your code hehe.

Also about randomizing speed on the waypoints, I highly recommend doing it after you've split up the paths in 100nm segments and before creating zigzags. The reason beaing that the game is already poor at maintaining formation in zig-zag turns and if you alter speed in the turns it gets even worse. It would look something like this


from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.loopProbability > 0:
waypoint.loopProbability = randint(2,8)
if waypoint.radius > 0:
waypoint.radius = 0
if waypoint.length > 500*1852:
zigZagToWaypoint(waypoint,i,0,100)
for waypoint in i:
waypoint.speed = randint(7,12)
if waypoint.length > 99*1852:
angle= randint(15,35)
distance= randint(12,50)
zigZagToWaypoint(waypoint,i,angle,distance)



thanks :up:

tater
05-19-07, 08:33 AM
Another thing to look at might be to set the zigzag distance to somethig based upon ship speed. If the convoy moves at 9 knots, then 4.5 nm would be every 30 minutes. Later in the war they might zig every 2.5 minutes sometimes. AI might not like that though.

tater

lurker_hlb3
05-19-07, 10:10 AM
Did a test run on this code

from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.loopProbability > 0:
waypoint.loopProbability = randint(2,8)
if waypoint.radius > 0:
waypoint.radius = 0
if waypoint.length > 500*1852:
zigZagToWaypoint(waypoint,i,0,100)
for waypoint in i:
waypoint.speed = randint(7,12)
if waypoint.length > 99*1852:
angle= randint(15,35)
distance= randint(12,50)
zigZagToWaypoint(waypoint,i,angle,distance)
Put the "randint" variable didn't make to the second "for waypoint in i" statement

I agree that the code needs "alot of cleanup" and I have made basic changes already


from random import randint
if group.repeatIntervalMinutes > 1:
group.repeatIntervalMinutes = randint(3000,10000)
if group.autoReportProbability > 1:
group.autoReportProbability = randint(5,25)
if group.autoReportInterval > 1:
group.autoReportInterval = randint(1440,9999)
if group.spacing > 1:
group.spacing = randint(500,995)


i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.loopProbability > 0:
from random import randint
waypoint.loopProbability = randint(2,8)
if waypoint.radius > 0:
waypoint.radius = 0
if waypoint.length > 250*1852:
zigZagToWaypoint(waypoint,i,0,100)

from random import randint
for waypoint in group.waypoints:
waypoint.speed = randint(7,12)

i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.length > 99*1852:
from random import randint
angle= randint(15,35)
distance= randint(12,50)
zigZagToWaypoint(waypoint,i,angle,distance)

tater
05-19-07, 03:24 PM
For TFs, the first thing that needs to happen is that thelarge tanker needs the max speed (Sea/NOL_Nippon/NOL_Nippon.cfg) changed to 19 since 12 is too low.

Then the GENERIC Tanker entries need to be switched for the large tanker exclusively.

At that point, I'd have all TFs steaming at between 15 and 17 knots.

For the troopships, I'd make the speed below their max speed, but still pretty high. If the code was capable of looking at the total path length of the group, perhaps the speed might be inversely proportional to distance. If the trip is really short, have them make maximum speed, dropping to maybe 15 knots minimally for a really long haul.

Yanaran
05-19-07, 04:10 PM
For TFs, the first thing that needs to happen is that thelarge tanker needs the max speed (Sea/NOL_Nippon/NOL_Nippon.cfg) changed to 19 since 12 is too low.

Then the GENERIC Tanker entries need to be switched for the large tanker exclusively.

At that point, I'd have all TFs steaming at between 15 and 17 knots.
One of the first things I did when this tool was release was I removed all tankers from task forces in the same way like lurker_hlb did for convoys, see mcoca's post on page2 for code to do it. I then gave them a random speed between 15 and 18 knots on each waypoint and works great! :D

lurker_hlb3
05-21-07, 05:13 PM
Here some test code that I'm working on, it's for Japanese Convoys ( 41a / 42a /42b /43a / 44a / 44b.

I've play test this and some other code for Merchants / TF / SubHunters, and let be the one to tell you, "patrols" are no longer boring.
Wow, those are pretty extensive changes. I have created a monster! ;)

Seeing the kind of things people are doing, next version will definitely have a "run script from file" option. Let's see if I have time to put it together tomorrow.


Any ETA on the next update on your program ?

mcoca
05-21-07, 05:22 PM
Any ETA on the next update on your program ?
I'm debugging it. I implemented all the features I wanted over the weekend, but cloning groups gives an odd error message. So, I'll release as soon as I can spare a couple of hours to debug, fix and pack it.

But don't worry, I expect it'll ready before 1.3 :lol:

lurker_hlb3
05-21-07, 06:13 PM
Any ETA on the next update on your program ?
I'm debugging it. I implemented all the features I wanted over the weekend, but cloning groups gives an odd error message. So, I'll release as soon as I can spare a couple of hours to debug, fix and pack it.

But don't worry, I expect it'll ready before 1.3 :lol:

Thanks

tater
05-24-07, 09:22 AM
While I think this is an issue of using code within the program, I will throw it out there because it might generate some thought for other features.

It would be interesting to make a group with multiple independant units.

Ie:
1. you make a "primary" group, and plot waypoints. Program even zig-zags them.
2. clone group with a spacing offset and the code would place each ship X meters from the selected "primary" in a pattern (1 column, 2 columns, etc).

Obviously if the groups were multiple ships this might cause a problem, but if the group was a single ship, it'd be fine. You could then make a TF where some ships peel off. Or with enough offset, you have a BB TF with organic escorts. There could also be a borrowed DesDiv of 4 DDs that zig-zags out in front, then peels off for a different mission.

For convoys (this is where the idea in my head came from) you make a group with a single merchant and escorts (set to position as escorts). The rest of the merchants are individual ships. Convoy attacked, and the rest might move on... Alternately, say you made 4 groups. The lead ship in each is a merchant, and they are offset by the code to form a 750m box. Each of the merchants has a single escort of some type (subchaser, minelayer, DD).

Interesting to see how the AI would deal with an attack in this situation.

MudMarine
05-27-07, 10:48 AM
Skippers,
This from just a newbie like myself is amazing stuff. Yet is beyond my understanding of the code. I have done some simple stuff with XML editor for Galatic Civilizations and Kdiff3 for merging Rome Total War files and used a note editor, just minor stuff really.

Can the changes this tool produce be made into a Mod for the campaign? If so it would be great for us other code illiterate skippers out there, like myself.

tater
05-27-07, 11:01 AM
Oh yeah. This is an amazing tool to redo the campaign layers. To be fair to the devs, making all the traffic required for the entire war is a daunting task in the Pacific because unlike the Atlantic, it changes constantly (in the Atlantic the volume/nature of traffic might change, but the routes are pretty much constant after the fall of France).

The basic idea they executed, splitting the layers into segments based on date/content is a good one, the only real issue is the content, and some of the routes and lack of routes.

I've already made an experimental set using lurker's code in mcoca's program that adds zig zags to all the japanese stuff in the campaign. I guess I could make it available, but it's very much a WIP.

MudMarine
05-27-07, 02:03 PM
I hope you get it worked out. Maybe the devs will fix that, likely not.

Mav87th
05-27-07, 06:26 PM
It would be REALLY cool if you could make an area "hot" and have frighters avoid it and ASW forces drawn to it.

Like if you are around Okinawa's western side and sink a couple of freighters - now freighters pick an alternative route to Okinawa while ASW's beare in on that area. Forcing you to move your patrol area both in search of new pray and to avoid getting clubbered.

lurker_hlb3
06-12-07, 08:38 PM
Any ETA on the next update on your program ?
I'm debugging it. I implemented all the features I wanted over the weekend, but cloning groups gives an odd error message. So, I'll release as soon as I can spare a couple of hours to debug, fix and pack it.

But don't worry, I expect it'll ready before 1.3 :lol:

bump

tater
06-12-07, 10:26 PM
Lest anyone forget. This program is up there with minitweaker and JSGME.

<S> to all the guys doing the unheralded heavy lifting.

tater
06-13-07, 12:05 PM
Hey, how would I code it to randomize waypoint.speed, but only if the speed for the given waypoint is > some number (say 5)?

I tried:

from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.speed > 5:
waypoint.speed = randint(6,10)

but it doesn't work

mcoca
06-13-07, 12:35 PM
Hey everyone, sorry the promised release didn't arrive.

Actually, I have all the coding changes ready, it only needs documenting the new features. Unfortunately, real life interrupted me, and I never got around to it. Let's see if I can write something tonight and release.

Meanwhile, tater, it's really nice to see people actually using this in released mods :up:

mcoca
06-13-07, 12:36 PM
Hey, how would I code it to randomize waypoint.speed, but only if the speed for the given waypoint is > some number (say 5)?

I tried:

from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.speed > 5:
waypoint.speed = randint(6,10)
but it doesn't work
You are missing an indentation (white space counts in python!):


from random import randint
i = group.waypoints.iterator ()
for waypoint in i:
if waypoint.speed > 5:
waypoint.speed = randint(6,10)

tater
06-13-07, 12:46 PM
thx! got it!

wildchild
06-13-07, 01:25 PM
Will This Work On Sh3 :d

mcoca
06-13-07, 01:42 PM
Will This Work On Sh3 :d
I think SH4 added some fields to the SH3 file format. Since the program expects them to be there, it probably won't work. However, making a SH3-compatible version should be very easy.

If someone tries it, just let me know.

mcoca
06-13-07, 05:15 PM
New version released at last. See first post for details.

lurker_hlb3
06-13-07, 08:06 PM
found a bug using the "script" option. Injected the following code using "script" option and software displayed "error" message. used the same in the "group change" field and software worked as designed

if group.groupName.find("Merchants") != -1:
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.CARGO:
i.remove ()
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.TANKER:
i.remove ()


also


request a working example of the following code

moveGroup(group,1000,2000)


and



i = mission.randomGroups.iterator ()
for group in i:
i.insert (group.clone ())


Thabks in advance

mcoca
06-14-07, 03:06 AM
found a bug using the "script" option. Injected the following code using "script" option and software displayed "error" message. used the same in the "group change" field and software worked as designed

if group.groupName.find("Merchants") != -1:
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.CARGO:
i.remove ()
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.TANKER:
i.remove ()

When you insert code in the "group change", the program turns it into something like this:


i = mission.randomGroups.iterator ()
for group in i:
[[group change code]]

The script mode has no such loops defined, so you need to add them explicitly. In your case:


group_iter = mission.randomGroups.iterator ()
for group in group_iter:
if group.groupName.find("Merchants") != -1:
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.CARGO:
i.remove ()
i = group.units.iterator ()
for unit in i:
if unit.type == UnitType.TANKER:
i.remove ()

The advantage of script mode is that you can write a complete program, including defining you own functions. So you write the previous code in this way (untested, may contain typos):


def removeShips (group, type):
i = group.units.iterator ()
for unit in i:
if unit.type == type
i.remove ()

group_iter = mission.randomGroups.iterator ()
for group in group_iter:
if group.groupName.find("Merchants") != -1:
removeShips(group, UnitType.CARGO)
removeShips(group, UnitType.TANKER)

Which is, IMO, much cleaner.


request a working example of the following code

moveGroup(group,1000,2000)


and



i = mission.randomGroups.iterator ()
for group in i:
i.insert (group.clone ())

This happens when you write the docs from memory, sorry :) This script works fine on a sample mission with a single group:


i = mission.randomGroups.iterator ()
for group in i:
clone=group.clone()
moveGroup(clone, 100000, 100000)
i.add(clone)


Hope this helps,

lurker_hlb3
06-14-07, 07:23 AM
Tried this in the group change area

but gave the following error "unexpected error: java.util.ConcurrentModificationException:null

i = mission.randomGroups.iterator ()
for group in i:
clone=group.clone()
moveGroup(clone, 100000, 100000)
i.add(clone)

mcoca
06-14-07, 07:31 AM
Tried this in the group change area

but gave the following error "unexpected error: java.util.ConcurrentModificationException:null

i = mission.randomGroups.iterator ()
for group in i:
clone=group.clone()
moveGroup(clone, 100000, 100000)
i.add(clone)
Yes, I know. With the cloning, I hit the limit of what I can do transparently by mixing loops in Java and Python (for the group change), without complicating things further. So, the cloning is only usable from the script mode.

There may be some way around it, but I'm satisfied with the current solution, since I think anyone making complex changes should be using the script mode anyway. If yuo want to find a fix, check the source (it's in src/net/sf/shbatcheditor/editor/changes/JythonRndGroupChange.java).

lurker_hlb3
06-14-07, 04:59 PM
The problem I'm having right now is that there are not any "samples" of script code.
I've made some fairly complex changes with the scripts that I created with the last version.

Was able to get a lot of ideas from the "campaignchanges.py" when working with v0.3 how ever can't find the same with this version.

since my last post found out that the cloning only works with "script" mode and have hacked some of my old code to work with "scripts" based on one of your other post.

current problem is it doesn't like "from random import randint" call and throws out an error.


Request a set of example so I can get my bearing and start using you great tool


Thanks in Advance

mcoca
06-14-07, 05:18 PM
Was able to get a lot of ideas from the "campaignchanges.py" when working with v0.3 how ever can't find the same with this version.

since my last post found out that the cloning only works with "script" mode and have hacked some of my old code to work with "scripts" based on one of your other post.

current problem is it doesn't like "from random import randint" call and throws out an error.
You are probably using it from inside a loop, and it doesn't like it (I was quite surprised that it worked in the past).


Request a set of example so I can get my bearing and start using you great tool
Okay, as a general rule, a script should look like this:


# Imports at the top
from random import *

# Any function definitions you want to create:
def removeShips (group, type):
i = group.units.iterator ()
for unit in i:
if unit.type == type
i.remove ()def removeShips (group, type):

# Loop over the groups
i = mission.randomGroups.iterator ()
for group in i:
# What used to be in the "group change" box, except for imports, goes here,
# with the proper indentation
removeShips(group, UnitType.CARGO)
clone=group.clone()
moveGroup(clone, 100000, 100000)
i.add(clone)

You can, of course, be more creative: move the loop into a function defition, create several loops, etc. But that's the equivalent of what was going on before.

Hope this helps.

lurker_hlb3
06-14-07, 06:02 PM
Thanks for your help, based on your last post was able to get one of my key scripts to now work in "script" mode.

PS

Hate the "White Space" rules, got so many "snytax" errors I though I was going put my fist through the monitor

mcoca
06-14-07, 06:13 PM
Thanks for your help, based on your last post was able to get one of my key scripts to now work in "script" mode.

PS

Hate to "White Space" rules, got so many "snytax" errors I though I was going put my fist through the monitor
Get a good programming editor that supports python ;) There must be a couple dozen free ones around.

And I know whitespace control can be frustrating. But so can be figuring out why the following C/C++/Java/C# code also increments negative numbers (trivial example follows):


if ( x > 0)
x = x * 2;
x = x + 1;

The first time you find that in someone else's code you have to debug, you'll miss python style control ;)

lurker_hlb3
06-14-07, 07:00 PM
Using "EditPad Pro" now vice "EditPad Lite", change out the other 5 scripts in about 10 minutes

Thanks again for the help

tater
07-12-07, 06:28 PM
having a problem with "cargoExt & cargoInt". When I use/change them get "error" saying that these item are read only. Was using them in contection with editing / creating merchants.
I expanded the internal names to "internalCargo" and "externalCargo". I have no idea why the error is so silly...

is there code to "randomly" selecting "crewratings" ?
Not per se, but it's really easy to create your own:



unit.crewRating=choice((CrewRating.POOR, CrewRating.NOVICE, CrewRating.COMPETENT))


That will select a random element from that list. Add or remove elements at will. You can also edit init.py to add a function that does that as shorthand.
Can you create a list with the same entry twice?

For example:

unit.crewRating=choice((CrewRating.COMPETENT, CrewRating.COMPETENT, CrewRating.COMPETENT, CrewRating.COMPETENT, CrewRating.COMPETENT, CrewRating.COMPETENT, CrewRating.VETERAN, CrewRating.VETERAN, CrewRating.VETERAN, CrewRating.ELITE))


The idea would be that without other coding it would quickly give a 10% chance of Elite, 30% vet, 60% Competant.

tater

keltos01
01-22-09, 06:04 AM
nice work !

keltos

ivank
02-07-09, 11:16 PM
may I still use this?

tater
02-08-09, 02:46 AM
Why not? He wrote it as a tool for people. And an awesome tool it is!

keltos01
09-20-10, 05:12 AM
I'm gonna see what this thing does ;)

keltos

tater
09-20-10, 08:01 AM
It does... a lot.

keltos01
09-20-10, 12:19 PM
It does... a lot.

can't even seem to be able to load the program ! :wah::har::wah:

tater
09-20-10, 04:47 PM
Odd. It uses scripting, so you might need to have the right frameworks set up. Check the readme.