I was thinking like 4 weapons packs, 4 weapons each. (Most people don't use all 6 eden weapons anyways)
Leave ore deposits, base layout's exactly the same (this way you wouldn't have the issues of the experienced player gets a 3 bar common, and the rookie gets a 1 bar
I like the idea of Random deadly disasters, once every 300 game marks, and yeah a volcano that could randomly erupt which brings up a good question, setting lava tiles goes something like this
// Function for Setting All S1 and S2 Celltypes to lava-possible
void SetAllLava()
{
int x, y, tile;
LOCATION mapsize(512, 256); // create a point wayoff the map
mapsize.Clip(); // clip it, so we have the mapsize
for (y = 0; y<mapsize.y; ++y) // run through all rows
{
for (x = 0; x<mapsize.x; ++x) // check every tile on each row
{
tile = GameMap::GetCellType(LOCATION(x, y)); // get the celltype on that position
if ((tile == cellSlowPassible1)
|| (tile == cellSlowPassible2)) // If celltype = S1 or S2
{
GameMap::SetLavaPossible(LOCATION(x, y), true); // -> then set it to LavaPossible
}
}
}
}
It would be more tedious but I guess you could put this code :
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(76 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(76 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(76 + 31, 41 - 1), true);
...in 4 or 5 packs that the game could randomly call upon to distribute lava down, again pain in the arse to type all that code up, but then this way the lava goes somewhere different each time.
Enough consistency you don't get pissed playing the game, but enough changes its a different experience each time.
And as for weapons packs, 3 or 4 types in each?
- Laser, EMP, ESG, Rocket
- Microwave, Nova, Starflare, Thor
- Microwave, Sticky, Rail, Acid
- Laser, Sticky, Acid, ESG
And one more thought.
If a six player map does not have all six human players selected, should the other two or three spots be filled by AI?
Suggestions?
The Lava on this simple colony map I have is a mix of what I found on Sirbomber's tutorials, and a post by you Hooman
// Function for Setting All S1 and S2 Celltypes to lava-possible
void SetAllLava()
{
int x, y, tile;
LOCATION mapsize(512, 256); // create a point wayoff the map
mapsize.Clip(); // clip it, so we have the mapsize
for (y = 0; y<mapsize.y; ++y) // run through all rows
{
for (x = 0; x<mapsize.x; ++x) // check every tile on each row
{
tile = GameMap::GetCellType(LOCATION(x, y)); // get the celltype on that position
if ((tile == cellSlowPassible1)
|| (tile == cellSlowPassible2)) // If celltype = S1 or S2
{
GameMap::SetLavaPossible(LOCATION(x, y), true); // -> then set it to LavaPossible
}
}
}
}
// Functions for setting up volcano animations
void SouthFlowAni(int x, int y)
{
GameMap::SetTile(LOCATION(x, y), 0x474);
GameMap::SetTile(LOCATION(x, y + 1), 0x47E);
}
I kind of prefer setting lava by cell type rather then tile color, I can make the lava flow exactly where I want it (and the map editor is already frustrating and time consuming, switching to the cell type layer is simple and quick)
int InitProc()
{
//Set tiles on map to lava possible
SetAllLava();
// Script used for changing tiles on side of volcano to lava possible
// Eruption starts the actual eruption and gets the lava flowing
SCRIPT_API void Eruption()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(76 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(76 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(76 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(76 + 31, 39 - 1, 2300);
TethysGame::SetLavaSpeed(150);
}
As for AI, at first it would just be simple filler for the map, if we want to add some curious behavior to it, I guess we can do that later.
And yeah no harm. As long as people help and have good suggestions, say what ever you want.
So here's some code I could use some help cleaning up.
It's all for testing purposes right now and it's a little lengthy...
This code creates a Volcano at one of 7 pre-selected locations, randomly at Mark 11. Actually spreading Lava I'll declare all at once, and I hope to use this structure of code, or a similar structure for other events.
Before Init_Proc
void VolA()
{
// Start a south volcano animation
SouthFlowAni(70 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 100, "EruptionA");
return;
}
void VolB()
{
// Start a south volcano animation
SouthFlowAni(80 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 120, "EruptionB");
return;
}
void VolC()
{
// Start a south volcano animation
SouthFlowAni(90 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 130, "EruptionC");
return;
}
void VolD()
{
// Start a south volcano animation
SouthFlowAni(100 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 140, "EruptionD");
return;
}
void VolE()
{
// Start a south volcano animation
SouthFlowAni(110 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 150, "EruptionE");
return;
}
void VolF()
{
// Start a south volcano animation
SouthFlowAni(120 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 160, "EruptionF");
return;
}
void VolMid()
{
// Start a south volcano animation
SouthFlowAni(130 + 31, 37 - 1);
// Start the eruption on it's way in 1 mark
Trigger &timeTrigger = CreateTimeTrigger(true, true, 170, "EruptionMid");
return;
}
void (*volcanos[7])() = { VolA, VolB, VolC, VolD, VolE, VolF, VolMid };
In Init_Proc
(*volcanos[TethysGame::GetRand(7) % 7])();
After Init_Proc
SCRIPT_API void EruptionA()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(70+ 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(70 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(70 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(70 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionB()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(80 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(80 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(80 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(80 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionC()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(90 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(90 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(90 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(90 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionD()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(100 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(100 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(100 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(100 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionE()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(110 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(110 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(110 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(110 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionF()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(120 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(120 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(120 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(120 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
SCRIPT_API void EruptionMid()
{
// Mark where the lava can flow
// (do this anytime before the eruption, including from InitProc)
GameMap::SetLavaPossible(LOCATION(130 + 31, 39 - 1), true);
GameMap::SetLavaPossible(LOCATION(130 + 31, 40 - 1), true);
GameMap::SetLavaPossible(LOCATION(130 + 31, 41 - 1), true);
// Start the lava flowing (... in about 10 marks)
// At this point, the earliest disaster warning will sound
TethysGame::SetEruption(130 + 31, 39 - 1, 200);
TethysGame::SetLavaSpeed(150);
}
It works, and it works fine... just lengthy.
Thoughts?
EDIT: so I just read some of Mcshay's smartlava post, I am way behind on good lava I think... This code is terrible...
DOUBLE EDIT: So I have changed this code just a little, and adjusted it too watch whats going on. It randomly pics a location to dump the lava, but it always starts a mark 11, animation shows up at Mark 1, lava at 11 everytime. Damn...
ZigZagJoe did meteor showers in his maps and I mostly just found it to be incredibly annoying when you get spammed with a dozen "meteor approaching" warnings all at the exact same instant.
When you create the disasters, you can memory hack the units to mark them as already having warned you. Do that for all but maybe one of them to prevent spam.
For those that are wondering, when you create a disaster, there is a 10 mark delay before it appears. This is to give the game time to provide the advanced warnings, once the corresponding advanced warning is researched at a lab.
@dave_erald:
As for the code, yes, that can be compressed. I'm a little surprised to see you making use of function pointers. That's normally considered a somewhat advanced topic.
As for how I would do it, I'd create an array of data, rather than an array of function pointers. The code is essentially the same between all copies, only the hardcoded data changes. Instead, remove the hardcoding from the functions, use variables, place the hardcoded data into an array, and randomly select an element from the array to be used in the function.
const Point volcanoLocations[] = {
{70, 37},
{80, 37},
{90, 37},
...
};
// In InitProc, or TimeTrigger callback, or wherever:
CreateEruption(volcanoLocation[TethysGame::Rand(NumOf(volcanoLocations))]);
void CreateEruption(Point &pt)
{
// Create eruption
SouthFlowAni(pt.x + 31, pt.y - 1);
TethysGame::SetEruption(pt.x + 31, pt.y - 1);
}
Here I'm setting the animation at the same time as alerting the game of the eruption. I feel it would make more sense to the player if these two events were tied closely together, having the visual indication of a volcano erupting, and the advanced alert of a pending eruption. You can also set lava possible bits if needed in that function, but usually the eruption is placed somewhere you'd expect those bits to already be set.
To delay eruption after game start, use CreateTimeTrigger in InitProc, with the desired delay, and place the code that calls CreateEruption inside the callback function for the time trigger.
The newer SDK uses "Export" to mark the callback functions for export from the DLL, rather than "SCRIPT_API".
Oh, and you're a little inconsistent with the indentation of your braces {}. They are usually not indented to the same level as their contents. Opinions vary on that, but most people would put them at the same tab stop as the outside of the block. To reduce the number of lines, sometimes the opening brace is at the end of the line above.
// The usual way
if (condition)
{
// Contents
}
// The compact way
if (condition) {
// Contents
}
// The somewhat strange and uncommon way
if (condition)
{
// Contents
}
Here's the completed code that compiles and runs just fine:
POINT volcanoLocations[] = {
{ 112, 37 },
{ 114, 37 },
{ 116, 37 },
{ 118, 37 },
{ 120, 37 },
{ 122, 37 },
{ 124, 37 },
};
void CreateEruption(POINT &pt)
{
// Create eruption
SouthFlowAni(pt.x + 31, pt.y - 1);
TethysGame::SetEruption(pt.x + 31, pt.y - 1, 300);
TethysGame::SetLavaSpeed(150);
}
In InitProc:
CreateEruption(volcanoLocations[TethysGame::GetRand(7)]);
Which is waaaaaaay cleaner than the dribble of crap I was trying to do.
Side note, the TethysGame::SetLavaSpeed is sorta useless ain't it? (Yes it is, that 300 in TethysGame::SetEruption is the lava speed, 50 is slow, 500 is, well, lava probably shouldn't move that fast...)
NEXT=> A lot of this could be used for a controlled meteor shower right? All of the meteor impact points would go in:
POINT meteorShowerA[] = {
{105,40},
{110,41},
{115,42},
...
};
POINT meteorShowerB[] = {
{120,40},
{125,41},
{130,42},
...
};
POINT meteorShowerC[] = {
{135,40},
{140,41},
{145,42},
...
};
POINT meteorShowerD[] = {
{150,40},
{155,41},
{160,42},
...
};
void CreateMeteor(POINT &pt)
{
TethysGame::SetMeteor(pt.x + 31, pt.y - 1, 2);
}
CreateMeteor(meteorShowerA[TethysGame::GetRand(3)]);
CreateMeteor(meteorShowerB[TethysGame::GetRand(3)]);
CreateMeteor(meteorShowerC[TethysGame::GetRand(3)]);
CreateMeteor(meteorShowerD[TethysGame::GetRand(3)]);
I would have to look into how you would randomly shift the entire meteor shower around to different locations, and disable the bazillion warnings you would get.
As always Thanks Hooman!
Doing that still spams you with warnings (disaster occurring), just not cautions (disaster watch, 10 marks prior) or alerts (disaster imminent, 5 marks prior).
Good point Arklon. Perhaps some more thinking is required.
Side note, the TethysGame::SetLavaSpeed is sorta useless ain't it? (Yes it is, that 300 in TethysGame::SetEruption is the lava speed, 50 is slow, 500 is, well, lava probably shouldn't move that fast...)
I think so, yes. That's why I omitted it.
NEXT=> A lot of this could be used for a controlled meteor shower right? All of the meteor impact points would go in:
That "MeteorShowerA/B/C" looks an awful lot like an array. ;)
As for the meteor shower offsets, it's similar to how it's done with the volcano. From what I remember, SouthFlowAni sets two tiles to animate. You specify one coordinate, and the other coordinate is offset from there. The meteor shower cloud could have relative coordinates from a center point. You specify a center point to the function, and the function will spawn meteors about that center point. The offsets could be controlled by using set layouts, passed in an array, or they can be randomly generated. The layout idea is neat, but beware the player will quickly recognize those layouts if you don't have a lot of them. That might not be desirable. It does allow for control over the damage pattern though, and can prevent two or three meteors from overlapping, and possibly causing too much localized damage.
void CreateMeteorShower(POINT ¢er, int numMeteors, POINT offsetList[])
{
for (int i = 0; i < numMeteors; ++i) {
POINT pt = center + offsetList[i];
int meteorSize = 2; // Better not to hardcode this
TethysGame::SetMeteor(pt.x + 31, pt.y - 1, meteorSize);
}
}
A modification to the above, is rather than pass "POINT offsetList", is to define a new data structure that contains both the offset, and the size of the meteor. That way it's not always hardcoded to 2. Such a struct might look like this:
struct MeteorInfo {
POINT pt;
int size;
};
You can then use array[index].pt, and array[index].size to control the offset and size of the meteor.
A further extension might include varying time delays, so the meteors don't all crash down at exactly the same time. I think that would actually be rather important to give the meteor shower some flavour. I'll leave you to think about it first. It will likely involve using scriptGlobal to control placement over multiple game ticks.
You can do away with the layout array by just using random numbers to generate the offsets. A parameter might be the size of the area around the center where meteors can hit. You can also play around with random number distributions to get meteors more likely near the center, and only rarely near the edges, and shape the area so it's more circular, or oval, or linear, rather than a box. There are also ways of controlling layout to prevent crowding, but you'd likely need to generate and store coordinates in an array and then spawn the meteors after all of them have been assigned a place. If you're also doing time delays, then the array will need to be stored between ticks, again using scriptGlobal.