wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Resources > Tools
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 06-21-2009, 10:01 AM   #1
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default GMSI

Finally, I want to add my tool here.

Since I have used it in many projects and it seems to work fine now I present it here. It is also able to inject itself into JNGP allowing easier usage.

An (outdated) discussion can be found in my old presentation thread:
http://www.wc3c.net/showthread.php?t=103939

This short presentation is copied from that thread:


Introduction


I want to present my latest tool GMSI to you. It is an advancement of my old tool GOSI, which I presented here, but I just earned some bad criticism. Well the old tool DID suck I admit.
However, it was already mighty enough to help me greatly with making my maps. As you might remember, I am the author of the (more or less) well-known maps Castle Fight and eeve!TD. I have used GOSI for creating those maps and it freaking helped me alot.

Okay, before I tell you what the program actually does, I will start with a story how the program evolved to what it is now:

History

As you might know, in my map Castle Fight there are 10 races with over 100 buildings and over 70 units.
I was getting tired of writing the tooltips for these units. So I made a program that could resolve Object Editor data in unit tooltips.
So I could just put some keywords in the tooltip and my tool unfolded them to the actual unit values.
So I just made one generic tooltip and added it to all units.
Then I thought: Why adding the tooltip to every unit? Can't I just make my program pick every unit and inject the tooltip into it? Well I could.

Next step:
There are many values which stay the same for every building. However, when I created new buildings I often forgot to change the values to these standards, which caused strange bugs.
So I thought:
If my program already picks all buildings and injects tooltips into them, can't I make to program also be able to change the unit values to what I want. It took some time then it worked.
The next thing was:
Every building has to be inserted with some parameters into an initialization trigger. That was damn copy and paste work for new buildings and I often forgot to change the parameters to the ones of the new building, so again, it caused strange bugs. Hell, can't also do my program that for me? ...*codecode*... well, now it can do it ;).

Finally I thought: Okay, now my program can alter triggers, arbitrary object editor data, can even create new objects. Why not take the final step and let the program be able to alter EVERYTHING in the map? After around one additional month of work it is now able to alter EVERYTHING in the map. It can alter object editor data, triggers, placed units/doods, regions, general map information, even the heightmap of the map. And that is GMSI now.

So you might ask? Okay, sounds like a GUI where you can change everything in a map. But isn't that just another world editor?
And the answer is of course no. The program has no GUI (well, it has, but not for editing maps). It is just an interpreter for a script language. This script language has the tools to load and save maps and alter them.

So what does the tool do?

It is just an interpreter for the script language called GSL. Before you start screaming: "What? Yet another scriptlanguage to learn?". NO, this script language is basically C with some small changes. So if you know C or JAVA you will need less than one hour to completely understand this language.

This script language is designed for altering wc3 maps exetremely simple and fast. To convince you that it is actually really useful, let me show you a few examples of how fast it can alter big parts of the map (remember the syntax is just like JAVA/C):

Examples

PHP Code:
Map map loadMap("myMap.w3x");      //Loads a map to the struct Map
map.objects.hpea.Ubertip "test";   //sets the peasant's ("hpea") ubertip to test
saveMap(map,"myChangedMap.w3x");     //Saves the map to a file 

As you can see, loading and saving a map is done in one line with the language. Doing a change is also done with one line by just accessing the members (and their submembers) of the struct Map.

Next example: altering many units using the foreach syntax lended from JAVA:
PHP Code:
Map map loadMap("myMap.w3x");  //Loads a map to the struct Map
for(string smap.objects){      //A loop iterating over the objects of the map
    
if(map.objects[s].HP != null)//Test if this object has Hitpoints (i.e. if it is a unit or item)
map.objects[s].HP 50;          //Change its HP to 50
}
saveMap(map,"myChangedMap.w3x"); //Saves the map to a file 
These 4 lines of code change the hitpoints of ALL units in your map to 50.
Okay that is silly but I can think of many useful scenarios:
Think of a Towerdefense where you want to set the hitpoints of lets say 100 waves of creeps to a formula like: LEVELē+10*LEVEL+100.
This would again be around 5-10 lines of code, you just have to filter units that are your creep waves (for example by checking if they are from a specified race), then getting their level and setting their hitpoints according to the formula.

Next example: Exchanging data between maps
PHP Code:
Map map loadMap("myMap.w3x");  //Loads a map
Map map2 loadMap("mySecondMap.w3x");
map.objects.h002 map2.objects.h005;
saveMap(map,"myChangedMap.w3x"); //Saves the map to a file 
This would take the user defined unit "h005" out of map2 and insert it with the id "h002" into the map "map".
So since we can load arbitrary many maps, we can transfer data between them as we want.

So without giving you the code for it, since you can alter anything in your map, let me think of some more examples:
-Generating random terrain by setting the heights/textures in an area and putting different doodads on it.
-Gathering information from many maps and assembling it to one map. This would be interesting for teamprojects, where one creates the triggers, the other one creates objects, the next one the landscape and so on. The script would then be a "makefile" that assembles all the data from the members to one map.
-Setting the map version / authors homepage: Maybe your map version / homepage is written in your load screen in the questlogs, somewhere in the GUI and in a welcome message. With a script you could change all these when the version/homepage changes.
-Creating beautiful generic tooltips (which the program was originally designed for)

Quick usage:

If I could convince you that this is useful indeed, and you want to try it, writing your own script then do the following:

Download the program and unzip it anywhere.
Start the GMSI.jar / GMSI.bat in the main directory.
Note that the program is written in Java, so you need an up to date JRE for it.
Choose a script and execute it.
Or write your own scripts and execute them :).
The program contains some small scripts to show you what is possible, like a "remove unused imports" script, that checks for every import your map has, if it is referenced somewhere in your map. If it isn't then it is removed.

For a full documentation on the Syntax and all possiblities the scriptlanguage/program offers, check the online manual (the manual is also included in the program's doc folder).


Links:

Download latest version



Online Manual


SUPPORT FORUM

New stuff:
The program is now at version 2.1.12. Many things have improved. It is now able to inject itself into JNGP generating a GMSI menu where you can execute the current map's script, taking and cropping a screenshot and opening a color picker.

It is able to alter everything. I currently use it for my latest project YouTD.

I am currently working on a picture API that allows you to open and save pictures, even in the blizzard used formats blp and tga. Thus it is possible to create and inject the loadingscreen automatically. Just load it from jpg, let the program cut it, save it als blps and import it. New loadscreen with just one click :).

Try it and gimme feedback,
thanks and best regards ;)
Attached Images
File Type: png GMSI logo.png (39.0 KB, 1697 views)
Attached Files
File Type: rar GMSI beta v2.1.16.rar (3.87 MB, 343 views)
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !

Last edited by gekko : 06-26-2009 at 05:06 PM.
gekko is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 06-21-2009, 12:31 PM   #2
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Code:
struct s = Size(); //Implicit "upcast"
Size t = (Size)s; //Explicit "downcast" 
excuse my dumb question, but isnt it right the other way round, the first line is an implicit downcast, and the second line is an explicit upcast?

Can this replace the object merger (assuming youre familiar with it)?
__________________

Last edited by Deaod : 06-21-2009 at 12:31 PM.
Deaod is offline   Reply With Quote
Old 06-21-2009, 02:40 PM   #3
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

In the first line I cast Size() up to its parent struct (so upcast). In the second line a cast a parent down to its child (downcast).

I am not too familiar with object merger. The stuff I have heard about it can surely be done by gmsi. As far as I know, it can do a lot more. It can basically do anything, even change the heightmap / terrain textures of your map.
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !
gekko is offline   Reply With Quote
Old 06-21-2009, 03:27 PM   #4
Toadcop
BuranX
 
Toadcop's Avatar
 
Join Date: Jul 2006
Posts: 1,886

Submissions (4)

Toadcop is just really nice (299)Toadcop is just really nice (299)

Approved Map: TcXSpell Making Session 10 Winner

Send a message via ICQ to Toadcop
Default

Quote:
map.objects.h002 = map2.objects.h005;
and what will happen if i have ability with rawcode h005 and unit ?! (afaik wc3 allows this. cause it's different scopes.)
__________________
Toadcop is offline   Reply With Quote
Old 06-21-2009, 04:22 PM   #5
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

Quote:
Originally Posted by Litany
In terms of manipulation this can do anything the ObjectMerger can do, but in terms of interface the ObjectMerger does some things this doesn't. Luckily the ObjectMerger already exists, so there's no reason for this to double its World Editor functionality anyway.
Of course. It was not meant as an replacement for object merger. It was meant as an interpreter in which you can procedurally alter anything about one or more maps.

Quote:
Originally Posted by Litany
I don't suppose this works on SLKs and TXTs in addition to object data files?
Well it gets its information of default object values from the WC3 SLKs and TXTs. There is no API for it yet, this is all done internally. However, since it is already done, it is no problem to code an API for reading data from SLK, if there is the need for this.


Quote:
Originally Posted by Litany
and what will happen if i have ability with rawcode h005 and unit ?! (afaik wc3 allows this. cause it's different scopes.)
I am not sure anymore if GMSI will throw an error or just do it.
It cannot handle if you have an Ability h005 AND a unit h005.
It will probably malfunction if your map contains more objects with the same ID. (It will just overwrite them with the last one loaded).
I have never seen maps where it was useful to have an ability h005 AND a unit h005.
However, if you only have an ability h005 and no unit h005 it should be no problem.

You can test for each object if it is an ability like this:

Code:
if (map.objects.h005 instanceof Ability) echo("H005 is an ability!");

To make it a bit more clear what this can be used to. Here is a script from my YouTD project that injects a tower from an XML file into a map.

As you can see, it can do really complex things. That's what it was meant for.
Code:
global int injectVersion = 7;

include("YouTD_header.gsl");
include("xml.gsl");
include("towerConstraints.gsl");
include("objects.gsl");
include("triggers.gsl");
include("commaList.gsl");
include("tableTooltips.gsl");
include("towerEvents.gsl");
include("string.gsl");

typedef Tower, TowerObject, TowerTrigger, TowerEffect, TowerTriggerValue,EventTrigger,EventParameter extern;

void applyPatternRecursive(var toResolve, string pattern, string replacement){
	if(toResolve instanceof struct){
		for(string t: toResolve){
			if(toResolve[t] instanceof string && toResolve[t]!=null) toResolve[t] = replaceAll(toResolve[t],pattern,replacement);
			else applyPatternRecursive(toResolve[t],pattern,replacement);
		}	
	} else if(toResolve instanceof array){
		for(int t: toResolve){
			if(toResolve[t] instanceof string && toResolve[t]!=null) toResolve[t] = replaceAll(toResolve[t],pattern,replacement);
			else applyPatternRecursive(toResolve[t],pattern,replacement);
		}
		for(string t: toResolve){
			if(toResolve[t] instanceof string && toResolve[t]!=null) toResolve[t] = replaceAll(toResolve[t],pattern,replacement);
			else applyPatternRecursive(toResolve[t],pattern,replacement);
		}
	}
}

void copyEntries(array from, array to){
	for(string s: from){
		to[s] = from[s];
	}
}

global string contentInjectPattern = "\\/\\/\\-\\-contentinjectpoint\\-\\-";
global string initInjectPattern = "\\/\\/\\-\\-initinjectpoint\\-\\-";
global array additionalPatternMapping = array();

int getNumItemSlots(string rarity, int goldcost){
	rarity = toLowerCase(rarity);
	int numSlots = 1;
	if(goldcost >= 400) numSlots++;
	if(goldcost >= 1200) numSlots++;
	if(goldcost >= 2000) numSlots++;
	if(rarity == "rare") numSlots++;
	if(rarity == "unique") numSlots+=2;
	return numSlots;
}


//makes all globals private
global string globalsPattern = "globals(.*)endglobals";


string escapeGlobalBlock(string input){
	array a = splitstr(input,"\n");
	string result = "";
	bool skip = false;
	bool erase = false;
	for(int i: a){
		if(skip){
			skip = false;
			result += a[i] + "\n";
			continue;
		}
		if(erase){
			erase = false;
			continue;
		}
		//Annotations
		if (matches(a[i],"\\s*\\/\\/\\@export\\s*")){
			skip = true;
			continue;
		}
		if (matches(a[i],"\\s*\\/\\/\\@import\\s*")){
			erase = true;
			continue;
		}
		
		if (matches(a[i],"(\\s*)|(\\s*\\/\\/.*)|(.*(^|\\s)private\\s.*)")){
			result += a[i] + "\n";
		}else{
			result += "\tprivate " + replaceAll(a[i],"public","") + "\n";
		}
	}
	return result;
}
string escapeGlobals(string input){
	array matches = findAll(input,globalsPattern);
	if(size(matches) == 0) return input;
	
	string result = "";
	int lastPos = 0;
	for(int i:matches){
		result += substr(input,lastPos,matches[i].start);
		result += "globals" + escapeGlobalBlock(matches[i].groups[1]) + "endglobals";
		lastPos = matches[i].end;
	}
	result += substr(input,lastPos);
	return result;
	
}

string escapeBuffIcon(string input, Map map){
	array matches = findAll(input,"\\.setBuffIcon\\(\\s*\\'(\\w{4})\\'\\s*\\)");
	for(int i: matches){
		string buffId = matches[i].groups[1];
		
		//Create tornado slow ability
		Wc3obj buffAbil = createObject(map,"Aasl");
		//Set base values
		buffAbil.DataA1 = 0.0;
		buffAbil.Area1 = 0.0;
		buffAbil.targs1 = "self,invulnerable,vulnerable";
		buffAbil.EditorSuffix = "";
		buffAbil.Name = "Effect abil for " + buffId;
		buffAbil.BuffID1 = buffId;
		
		//Transfer the effect from the buff to the ability (since we re using bugged tornado slow aura)
		Buff b = map.objects[buffId];

		buffAbil.TargetArt = b.TargetArt;
		buffAbil.Targetattach = b.Targetattach;
		if (b.TargetArt != "") b.TargetArt = "";		
		if (b.Targetattach != "") b.Targetattach = "";
		
		input = replace(input,"\\.setBuffIcon\\(\\s*\\'(\\w{4})\\'\\s*\\)",".setBuffIcon('" + getObjectId(buffAbil) + "','" + buffId + "')");
	}
	return input;
	
}

string implode(string separator, array a){
	string result = "";
	for(int i:a){
		result += a[i] + separator;
	}
	if(result == "") return result;
	return substr(result,0,strlen(result)-strlen(separator));	
}

string getACTooltip(TowerTrigger tt){
	float cool = (float)tt.values["AUTOCAST_cooldown"].value;
	float range = (float)tt.values["AUTOCAST_range"].value;
	int mana = (int)tt.values["AUTOCAST_manacost"].value;
	array a = array();
	if(mana>0) a[] = "|cffFFFF00" + mana + "|cffFFFF80 mana|r";
	if(cool>0.0) a[] = "|cffFFFF00" + format(cool) + "|cffFFFF80s cooldown|r";
	if (tt.values["AUTOCAST_autocastType"].value != "AC_TYPE_OFFENSIVE_IMMEDIATE") a[] = "|cffFFFF00" + format(range) + "|cffFFFF80 range|r";

	return "|n|cffA4AFD9Active:|n" + implode(", ",a);
}

//Creates an autocast
string createAutocast(string id,TowerTrigger tt, Map map){
		
		string acType = tt.values["AUTOCAST_autocastType"].value;
		
		//Create autocast ability
		Wc3obj acAbil = createObject(map,"ANcl");
		//Set base values
		acAbil.CasterArt = "";
		acAbil.EffectArt = "";
		acAbil.TargetArt = "";
		acAbil.DataD1 = 0.0;
		acAbil.DataF1 = "roar";
		acAbil.Order = "roar";
		acAbil.DataA1 = 0.0;
		acAbil.DataC1 = 1;
		acAbil.hero = 0;
		acAbil.levels = 1;
		acAbil.Hotkey = "A";
		
		//Check
		if (((float)tt.values["AUTOCAST_autoRange"].value >  (float)tt.values["AUTOCAST_range"].value) && (acType != "AC_TYPE_OFFENSIVE_IMMEDIATE"))  fail("The autocast range of your spell is larger then its spell range. This doesn't make sense for non immediate spells!");
	
		//Set the ability values
		acAbil.Cool1 = (float)tt.values["AUTOCAST_cooldown"].value;
		acAbil.Rng1 = (float)tt.values["AUTOCAST_range"].value;
		acAbil.Cost1 = (int)tt.values["AUTOCAST_manacost"].value;
		acAbil.Art = tt.values["icon"].value;
		acAbil.Name = id + " Autocast";
		acAbil.Tip = tt.values["name"].value;
		
		string addstring = "|n";
		if (acAbil.Cool1 > 0.0){
			addstring += "|n|cffFFFF00Cooldown: |cffFFFF80" + formatFloat(acAbil.Cool1) + " sec|r";
		}
		if (acType != "AC_TYPE_OFFENSIVE_IMMEDIATE"){
			addstring += "|n|cffFFFF00Range: |cffFFFF80" + formatFloat(acAbil.Rng1) + "|r";		
		}

		acAbil.Ubertip = tt.values["long_explain"].value + addstring;
		
		

		string eventHandler;
		string acTypeString;
		string targType;
		string suffix;
		if (acType == "AC_TYPE_ALWAYS_BUFF" || acType == "AC_TYPE_OFFENSIVE_BUFF"){
			acTypeString = "TYPE_BUFF";
			targType = tt.values["AUTOCAST_targetType"].value;
			if (matches(tt.code,"\\s*")){
				//No event handler? use 0
				eventHandler = "0";
			} else {
				eventHandler = "EventHandler." + id + "_" + eventTriggers[tt.name].handlerName;
			}
			suffix = "\tcall ac.setBuffType(" + tt.values["AUTOCAST_buffType"].value + ")\n";
			if (acType == "AC_TYPE_OFFENSIVE_BUFF"){
				suffix += "\tcall ac.setNumBuffsBeforeIdle(" + tt.values["AUTOCAST_numBuffsBeforeIdle"].value + ")\n";
				suffix += "\tcall ac.setAlwaysBuff(true)\n";				
			}
			
			//Target effect?
			if (!matches(tt.values["target_art"].value,"\\s*")){
				if (targType != "TARGET_TYPE_CREEPS"){
					//For towers do the target effect with triggers
					suffix += "\tcall ac.setTargetArt(\"" + escapeSlashesAddMdl(tt.values["target_art"].value) + "\")\n";
					if (targType == "TARGET_TYPE_PLAYER_TOWERS"){
						//Ability targets: player towers!
						acAbil.targs1 = "mechanical,player,invulnerable";
					} else {
						//Ability targets: team towers!
						acAbil.targs1 = "friend,mechanical,invulnerable";
					}
				} else {
					//For creep targets, do the target effect using the ability effect
					acAbil.TargetArt = tt.values["target_art"].value;
					//Ability targets: enemies!
					acAbil.targs1 = "enemies";
				}
			}
			
			//Set ability target type to "Units" (since were casting a buff which has to target a unit)
			acAbil.DataB1 = 1;
			
		} else {
			targType = "TARGET_TYPE_CREEPS";
			if (matches(tt.code,"\\s*")) fail("Autocast error: You haven't specified an event handler and your autocast is no buff. An autocast without an effect?");
			eventHandler = "EventHandler." + id + "_" + eventTriggers[tt.name].handlerName;
			
			//For creep targets, do the target effect using the ability effect
			acAbil.TargetArt = tt.values["target_art"].value;	
			
			//Set ability target type according to the acType
			if (acType == "AC_TYPE_OFFENSIVE_UNIT"){
				acTypeString = "TYPE_OFFENSIVE_UNIT";
				acAbil.DataB1 = 1;
				acAbil.targs1 = "enemies";
			} else if(acType == "AC_TYPE_OFFENSIVE_IMMEDIATE") {
				acTypeString = "TYPE_OFFENSIVE_IMMEDIATE";
				acAbil.DataB1 = 0;
			} else if(acType == "AC_TYPE_OFFENSIVE_POINT") {
				acTypeString = "TYPE_OFFENSIVE_POINT";
				acAbil.DataB1 = 2;
			} else {
				fail("Unrecognized autocast type: " + acType);
			}
			
		}
		
		//Caster art?
		if (!matches(tt.values["caster_art"].value,"\\s*")){
			suffix += "\tcall ac.setCasterArt(\"" + escapeSlashesAddMdl(tt.values["caster_art"].value) + "\")\n";	
		}
		
		//Create the result string
		string result = "\tlocal AutocastType ac = AutocastType.create(\"" + tt.values["name"].value + "\"," + eventHandler + ",'" + getObjectId(acAbil) + "',\"roar\",AutocastType." + acTypeString + ",TargetType.create(" + targType + ")," +  tt.values["AUTOCAST_range"].value
		+ "," +  tt.values["AUTOCAST_autoRange"].value
		+ "," +  tt.values["AUTOCAST_cooldown"].value + "," +  tt.values["AUTOCAST_manacost"].value + "," +  tt.values["AUTOCAST_isExtended"].value + ")\n" + suffix;
		result +="\tcall bt.addAutocast(ac)\n";
		
		return result;
}

global string pubFuncPattern = "(\\n|^)\\s*(?:public)?\\s*function";


global string initFuncPattern = "private function init takes nothing returns nothing(.*?)endfunction";


string createItem(Map map,Wc3obj twr){
	string id = getObjectId(twr);
	Wc3obj abyl = createObject(map,"AIbt");
	abyl.UnitID1 = id + "," + id + "," + id + "," + id;
	abyl.Name = "Build " + id;
	abyl.Dur1 = 1.0;
	
	Wc3obj itm = createObject(map,"tfar");
	itm.goldcost = twr.goldcost;
	itm.lumbercost = 0;
	itm.Ubertip = twr.Ubertip + "|n|n|cffFF8000You can morph another tower into this one by putting this item into its inventory!|r";
	itm.Description = "Used to create a tower";
	itm.Name = twr.Name;
	itm.Tip = "Buy " + twr.Name;
	itm.file = "Doodads\\LordaeronSummer\\Terrain\\Crates\\Crates1.mdl";
	itm.Art = twr.Art;
	itm.abilList = getObjectId(abyl);
	return ",'" + getObjectId(itm) + "'";
}


string injectTower(Tower tower,Map map, int pointVal,Wc3obj predecessor,bool createItem){
	string tooltip = "";
	if(pointVal < 100000) fail("The desired point value is too low!");
	
	//check script version
	if(tower.scriptVersion == null) fail("Your tower doesn't contain version information. Either it is corrupted or very old (pre beta 0.8)");
if(tower.scriptVersion < injectVersion) fail("Your tower is too old for this injection script. Reparse it with an up to date parsing script!\nTower version: " + tower.scriptVersion + "\nRequired version: " + injectVersion);
	//if(tower.scriptVersion > injectVersion) fail("Your tower is too new for this injection script. Get the latest injection script!\nTower version: " + tower.scriptVersion + "\nRequired version: " + injectVersion);
	
	//Check if all necessary settings are there
	if(tower.settings["authorDisplay"]==null||matches(tower.settings["authorDisplay"],"\\s*")) fail("You haven't entered authorDisplay! Enter authorDisplay (the name to be displayed in the tower's tooltip) in the Tower Config trigger!");
	if(tower.settings["element"]==null) fail("You haven't entered an element for your tower! Enter the element in the Tower Config trigger!");
	if(!matches(tower.settings["element"],"\\i(nature)|(fire)|(ice)|(darkness)|(astral)|(iron)|(storm)")) fail("Your tower's element is no valid element! Check the Tower Config trigger");
	
	if(tower.settings["rarity"]==null) fail("You haven't entered a rarity for your tower! Enter the rarity in the Tower Config trigger!");
	if(!matches(tower.settings["rarity"],"\\i(common)|(uncommon)|(rare)|(unique)")) fail("Your tower's rarity is no valid rarity! Check the Tower Config trigger");
	
	if(tower.settings["abil_factor"]==null) fail("You haven't entered an abil_factor for your tower! Enter the abil_factor in the Tower Config trigger!");
	if(!matches(tower.settings["abil_factor"],"(?:[0-9]+)|(?:[0-9]+\\.)|(?:[0-9]+\\.[0-9]+)|(?:\\.[0-9]+)")) fail("Your tower's abil_factor is no valid positive real number! Check the Tower Config trigger");
	
	if(tower.settings["authorDisplay"]==null||matches(tower.settings["authorDisplay"],"\\s*")) fail("You haven't entered authorDisplay! Enter 
	authorDisplay (the name to be displayed in the tower's tooltip) in the Tower Config trigger!");

	if(tower.settings["alpha"]!=null&&!matches(tower.settings["alpha"],"[0-9]+")) fail("The alpha value you have set for your tower is no valid number! Value: " + tower.settings["alpha"]);
	int alpha = (tower.settings["alpha"]!=null?(int)tower.settings["alpha"]:255);
	if(alpha > 255 || alpha < 0) fail("The alpha value of your tower is out of range. Must be between 0 and 255");
	
	//Create tower object
	Wc3obj twr = createObject(map,"hwtw",getFreeId(map,"hwtw"),false);
	string id = getObjectId(twr);
	//Create abilities and buffs and replace their appearances in the tower
	array abils = array();
	for(int i:tower.abilities){
		TowerObject a = (TowerObject)tower.abilities[i];
		abils[] = getFreeId(map,a.derivedFrom);
		createObject(map,a.derivedFrom,abils[],false);
		applyPatternRecursive(tower,a.id,abils[]);
	}
	for(int i:tower.buffs){
		TowerObject a = (TowerObject)tower.buffs[i];
		abils[] = getFreeId(map,a.derivedFrom);
		createObject(map,a.derivedFrom,abils[],false);
		applyPatternRecursive(tower,a.id,abils[]);
	}

	//Validate the tower data
	checkTowerConstraints(tower.oeValues);
	
	//Set tower data
	copyEntries(tower.oeValues,twr);	
	
	//Zero lumber cost
	twr.lumbercost = 0;
	

	//Check if the tower is expensive enough
	int goldcost = twr.goldcost;
	if (predecessor != null){
		if(twr.goldcost < predecessor.goldcost) fail("The tower is too cheap! It costs less than its predecessor, this may not be, make the tower more expensive!\nPredecessor: " + predecessor.Name + " cost: " + predecessor.goldcost +
	"\nTower: " + twr.Name + " cost: " + twr.goldcost);
		twr.goldcost = twr.goldcost - predecessor.goldcost;
	}
	
	//Set pointvalue
	twr.points = pointVal;
	
	//Set acquisition range if it is lower than the tower's attack range
	if(twr.acquire < twr.rangeN1) twr.acquire = twr.rangeN1;
	
	//Insert tower abilities
	int j = 0;
	for(int i: tower.abilities){
		copyEntries(tower.abilities[i].oeValues, map.objects[abils[j]]);
		//If tower doesnt have ability set  manacost to 0 (as it is probably a dummy ability)
		if(!listContains(abils[j],twr.abilList)){
			map.objects[abils[j]].Cost1 = 0;
		}	
		
		//Make sure that the ability has not more than 6 level and is no hero ability
		if(map.objects[abils[j]].levels > 6) fail("Your ability " + abils[j] + " has more than six0 levels, only abilities with six or less levels are allowed!");
		if(map.objects[abils[j]].hero == 1) fail("Your ability " + abils[j] + " is a hero abilitiy, you must make it a normal ability!");
		
		//Remove any requirements for abilities
		if(map.objects[abils[j]].Requires != "") map.objects[abils[j]].Requires = "";
		j++;
	}
	for(int i: tower.buffs){
		copyEntries(tower.buffs[i].oeValues, map.objects[abils[j++]]);
	}
	
	//Generate tooltip header
	if(!matches(twr.Ubertip,"\\s*")){
		tooltip = twr.Ubertip + "|n|n";
	}
	tooltip += "|cffFFFF00Author:|r " + tower.settings["authorDisplay"] + "|n";
	tooltip += "|cffFFFF00Damage:|r " + ((int)dps(twr)) + " dps, " + twr.atkType1  + "|n";
	tooltip += "|cffFFFF00Range:|r " + twr.rangeN1 + "|n";
	tooltip += "|cffFFFF00Speed:|r " + formatFloat(twr.cool1) + "|n";
	if(twr.manaN > 0) tooltip += "|cffFFFF00Mana:|r " + twr.manaN + " (+" + formatFloat(twr.regenMana) + "/s)|n";
	tooltip += "|cffFFFF00Specials:|r";	
	
	tooltip += generateTableTooltips(tower,map,twr);
	
	//Handle hovering / turning tower
	if(twr.moveHeight != 0.0 || twr.turnRate != 0.0){
		twr.movetp = "hover";
		twr.spd = 500;
		twr.isbldg = 0;
		twr.elevPts = 1;
		twr.elevRad = 10.0;
		if (twr.turnRate != 0.0){
			twr.abilList = listInsert(twr.abilList,"A006");
		} else {
			twr.abilList = listInsert(twr.abilList,"A007");
		}
	}
	
	//No model chosen? Choose normal tower model and make it totally invisible (to allow selection)
	if(twr.file == ".mdl" || twr.file == ".mdx"){
		alpha = 0;
		twr.file = "buildings\\other\\NerubianZiggurat\\NerubianZiggurat.mdl";
		twr.modelScale = 0.8;
	}
	
	//Balance tower
	balanceTower(tower,twr,false);
	
	//Set tower item slots
	twr.abilList = listInsert(twr.abilList,"INV" + getNumItemSlots(tower.settings["rarity"],twr.goldcost));

	
	//Add abilities (sell,invulnerable,tower level)
	twr.abilList = listInsert(twr.abilList,"Avul,XLVL,XSEL");
	
	//Build trigger injection strings
	string contentString = "";
	string initString = "\tset bt = EventTypeList.create()\n";
	string engineInit = "";
	array trigs = array();
	bool callIni = false;
	
	for(int i: tower.triggers){
		TowerTrigger t = (TowerTrigger)tower.triggers[i];

		//Explaining ability creation if visible = true
		bool show = false;
		bool autocast = false;
		if(t.name == "Autocast"){
			show = true;
			autocast = true;
		} else {
			t.values["visible"]!=null||fail("Missing trigger value \"visible\" in your trigger " + t.name);
			if((bool)t.values["visible"].value){
				show = true;
			}
			if(t.name == "Tower Aura"){
				t.values["name"]!=null||fail("Missing the name of your Aura. For auras, you have to set the \"name\" field in the trigger comment, even if you set visible to false (Auras must have a name)");
			}
		}
		
		//Visible was set, do the ability creation!
		if(show){
			t.values["name"]!=null||fail("Missing trigger value \"name\" in your trigger " + t.name);
			t.values["icon"]!=null||fail("Missing trigger value \"icon\" in your trigger " + t.name);
			t.values["short_explain"]!=null||fail("Missing trigger value \"short_explain\" in your trigger " + t.name);
			t.values["long_explain"]!=null||fail("Missing trigger value \"long_explain\" in your trigger " + t.name);
			string shortExplain = t.values["short_explain"].value;
			string longExplain = t.values["long_explain"].value;
			string icon = t.values["icon"].value;
			string name = t.values["name"].value;
			if(matches(name,"\\s*")) fail("You didn't specify a name for the event " + t.name);
			if(matches(icon,"\\s*")) fail("You didn't specify an icon for the event " + t.name);
			if(matches(shortExplain,"\\s*")) fail("You didn't specify a long explanation for the event " + t.name);
			if(matches(longExplain,"\\s*")) fail("You didn't specify an short explanation for the event " + t.name);
			
			//Create explainig ability for non autocasts
			if(autocast){					
				tooltip += "|n|n|cff80FF00" + name + "|r|n" + shortExplain + getACTooltip(t);
			} else {
				Ability explain = createObject (map, "Amgl");
				explain.Requires = "";
				explain.Name = id + " " + t.name;
				explain.Tip = name;
				explain.Ubertip = longExplain;
				explain.Art = icon;			
				twr.abilList = listInsert(twr.abilList,getObjectId(explain));
				tooltip += "|n|n|cff80FF00" + name + "|r|n" + shortExplain;
			}

		}
		
		
		
		if(t.name == "Header"){
			string headerContent = replaceAll(t.code,pubFuncPattern,"\n\tprivate function");
			Match m = find(headerContent,initFuncPattern);
			if (m == null) fail ("Didn't find the init function in your header library. Did you erase or rename it? (You may not do that. If you don't need the init then just leave it empty.)");
			//init function is empty, don't call it.
			if(!matches(m.groups[1],"\\s*")) callIni = true;
			headerContent = replaceAll(headerContent,initFuncPattern,"function " + id + "init takes nothing returns nothing$1endfunction");
			contentString = headerContent + "\n" + contentString;
			
		} else {
			trigs[t.name] = t;
			if (eventTriggers[t.name].handlerName != null){
				contentString += "\n\tfunction " + id + "_" + eventTriggers[t.name].handlerName + " takes Tower tower returns nothing\n\t\t" + t.code + "\n\tendfunction\n"; 
			}
			
			//Validate event parameters
			EventTrigger et = eventTriggers[t.name];
			for(string s:et.parameters){
				if (t.values[s] == null) fail("Missing event parameter: " + s);
				
				EventParameter pe = et.parameters[s];
				if(!matches(t.values[s].value,pe.pattern))  fail("Forbidden value for the global parameter " + s + " in trigger " + t.name + "!\nValue:" + t.values[s].value + "\nAllowed values:\n" + ep.description);
			}
		}
	}
	
	
	//Insert events (and validate their parameters
	TowerTrigger tt;
	if((tt = trigs["On Tower Creation"])!=null){
		initString +="\tcall bt.addEventOnCreate(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["On Tower Destruction"])!=null){
		initString +="\tcall bt.setEventOnCleanup(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["On Attack"])!=null){
		initString +="\tcall bt.addEventOnAttack(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + "," + tt.values["ONATTACK_chance"].value + "," + tt.values["ONATTACK_chanceLevelAdd"].value +  ")\n";
	}
	if((tt = trigs["On Damage"])!=null){
		initString +="\tcall bt.addEventOnDamage(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + "," + tt.values["ONDAMAGE_chance"].value + "," + tt.values["ONDAMAGE_chanceLevelAdd"].value +  ")\n";
	}
	if((tt = trigs["On Kill"])!=null){
		initString +="\tcall bt.addEventOnKill(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["Periodic"])!=null){
		initString +="\tcall bt.addPeriodicEvent(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + "," + tt.values["PERIODIC_period"].value + ")\n";
	}
	if((tt = trigs["On Spell Cast"])!=null){
		initString +="\tcall bt.addEventOnSpellCast(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["On Spell Target"])!=null){
		initString +="\tcall bt.addEventOnSpellTarget(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["On Level Up"])!=null){
		initString +="\tcall bt.addEventOnLevelUp(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + ")\n";
	}
	if((tt = trigs["On Unit Comes In Range"])!=null){
		initString +="\tcall bt.addEventOnUnitComesInRange(EventHandler." + id + "_" + eventTriggers[tt.name].handlerName + "," + tt.values["UNITINRANGE_range"].value +",TargetType.create(" + tt.values["UNITINRANGE_targetType"].value +"))\n";
	}
	if((tt = trigs["Tower Aura"])!=null){
		engineInit +="\t\tcall bt.addAura(AuraType.create(\"" + 
					tt.values["name"].value + "\"," +					
					tt.values["AURA_auraRange"].value + "," +
					tt.values["AURA_auraEffect"].value + ",TargetType.create(" +
					tt.values["AURA_targetType"].value + ")," +
					tt.values["AURA_targetSelf"].value + "," +
					tt.values["AURA_level"].value + "," +
					tt.values["AURA_levelAdd"].value +"," +
					tt.values["AURA_power"].value + "," +
					tt.values["AURA_powerAdd"].value + "))\n";
	}
	if((tt = trigs["Autocast"])!=null){
		engineInit += "\t\t" + createAutocast(id,tt,map);
	}
	
	
	//Add comment
	initString = "\n\n\t// TOWER: " + id + " (" + twr.Name + ")\n" + initString;

	//Damage table init
	if(size(tower.dmgTable)>0){
		string dmgTableInit = "\tset m = Modifier.create()\n";
		array dmgTable = tower.dmgTable;
		for(int i : dmgTable){
			dmgTableInit += "\tcall m.addModification(" + dmgTable[i].id + "," + dmgTable[i].base +"," + dmgTable[i].add +")\n";
		}
		dmgTableInit += "\tcall bt.setModifier(m)\n";
		initString += dmgTableInit;
	} else {
		initString += "\tcall bt.setModifier(Modifier.defaultModifier)\n";
  
	}
	
		
	//Inject the tower tooltip
	twr.Ubertip = tooltip;
	twr.Tip = "Upgrade to "+ rarityColors[tower.settings["rarity"]] + twr.Name + "|r";
	twr.Name = rarityColors[tower.settings["rarity"]] + twr.Name + "|r";
	
	
	//Add init footer
	string itemString = ",0";
	if(createItem)itemString = createItem(map,twr);
	initString += "\tset t = TowerType.create('"
				+ id + "'," 
				+ twr.manaN + "," 
				+ twr.regenMana + "," 
				+ (twr.dmgplus1 + ((1+twr.sides1)*twr.dice1)/2) + "," 
				+ twr.cool1 + "," 
				+ twr.rangeN1 + "," 
				+ goldcost + ",bt" + itemString + ",Rarity." + toUpperCase(tower.settings["rarity"]) + ",Element." + toUpperCase(tower.settings["element"]) + ")\n";

	//Init alpha value
	if(alpha != 255) {
		initString += "\tcall t.setColor(" + twr.red + "," + twr.green + "," + twr.blue + "," + alpha + ")\n";
	}
			
	//Effects init
	if(size(tower.effects)>0){
		initString += "\tset l = List.create()\n";	
		for(int i: tower.effects){
			
			TowerEffect te = (TowerEffect)tower.effects[i];
			if(te.z<0.0) fail("One of your effect models has negative z-value. Unfortunately this cannot be handled by the engine. Lift your models up to at least 0.0 z and retry!");
			initString += "\tcall l.addNew(TowerFXType.create(\""+
				escapeSlashesAddMdl(te.file) + "\"," +
				formatFloat(te.x) + "," +
				formatFloat(te.y) + "," +
				formatFloat(te.z) + "," +
				formatFloat(te.scale) + "," +
				formatFloat(te.rot) + "," +
				te.red + "," +
				te.green + "," +
				te.blue + "," +
				te.alpha + "," +
				formatFloat(te.pitch) + "))\n";
		}
		initString += "\tset t.effects = l\n";
	}

	//Call header ini if it is not empty
	if(callIni) initString += "\tcall "+ id + "init()\n";
	
	//Assemble content string
	contentString = "\n\n// TOWER: " + id + " (" + twr.Name + ")\nscope twr" +id + "\n" + escapeBuffIcon(escapeGlobals(contentString),map);
	if(engineInit != ""){
	initString += "\tcall "+ id + "engineinit(bt)\n";
	contentString += "\n\tfunction " + id + "engineinit takes EventTypeList bt returns nothing\n" + engineInit + "\tendfunction";
	}	
	contentString += "\nendscope";
	
	//Inject the code
	Trigger t = getTriggerByName(map,"libInject");
	if(t == null) fail("The trigger with the name libInject is missing");
	if(t.isComment) fail("The trigger with the name libInject is a comment!");
	if(!t.isCustomText) fail("The trigger with the name libInject is no custom trigger!");
	
	Match contentPoint = find(t.code,contentInjectPattern);
	if(contentPoint == null) fail("Didn't find the content injection point!");
	Match initPoint = find(t.code,initInjectPattern);
	if(contentPoint == null) fail("Didn't find the init injection point!");
	if(initPoint.start < contentPoint.start) fail("The content injection point is before the init injection point!");
	
	//Finally, do the injection
	t.code = substr(t.code,0,contentPoint.start) + contentString + substr(t.code,contentPoint.start,initPoint.start) + initString + substr(t.code,initPoint.start);
	
	return id;
}

__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !

Last edited by gekko : 06-21-2009 at 04:25 PM.
gekko is offline   Reply With Quote
Old 06-21-2009, 05:57 PM   #6
Toadcop
BuranX
 
Toadcop's Avatar
 
Join Date: Jul 2006
Posts: 1,886

Submissions (4)

Toadcop is just really nice (299)Toadcop is just really nice (299)

Approved Map: TcXSpell Making Session 10 Winner

Send a message via ICQ to Toadcop
Default

i don't care... i just wanted to point out what it shouldnt be map.objects but -> map.abilities, map.units etc. but it's your toy so you decide how to organize it.
__________________
Toadcop is offline   Reply With Quote
Old 06-21-2009, 11:05 PM   #7
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

Quote:
Originally Posted by Toadcop
i don't care... i just wanted to point out what it shouldnt be map.objects but -> map.abilities, map.units etc. but it's your toy so you decide how to organize it.

when I designed it I also asked myself if I should split things up. I chose not to do it because with only one object space you can iterate over all objects in just one loop. And I didn't think about people using the same ID for two different things (which I think is still not a real problem).
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !
gekko is offline   Reply With Quote
Old 06-22-2009, 01:35 AM   #8
darkwulfv
Alpha Male of Wc3c
 
darkwulfv's Avatar


Official Map Reviewer
 
Join Date: Mar 2006
Posts: 3,646

Submissions (6)

darkwulfv is just really nice (270)darkwulfv is just really nice (270)

Send a message via AIM to darkwulfv
Default

The only way an ability could have a rawcode id of 'h005' is if you object-editor hacked it to have that ID, which is probably pretty rare of an occurrance. Not saying it wouldn't happen, but...
__________________
The Spell Request Thread
Quote:
Originally Posted by Joe-Black-5
a dota like map but with unique stuff
(There was no map attached, and that was all the thread said.)
Spells I've Made

Darkwulfv's Lightning Grapple || Tritanis' Lazy Bolt

darkwulfv is offline   Reply With Quote
Old 06-22-2009, 07:39 AM   #9
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

SLK Files are not very complex. It should be easy to code a write API for them. (You could however, even write an API in the script language itself, since it allows arbitrary file access).

Can you give me some links / hints what it should do? Just dumping your object data to slk like the widgetizer or something else?
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !
gekko is offline   Reply With Quote
Old 06-22-2009, 04:21 PM   #10
PitzerMike
Alcopops
 
PitzerMike's Avatar


Tools & Tutorials Moderator
 
Join Date: Jan 2003
Posts: 2,794

Submissions (12)

PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)

Approved Map: Pitzer's Minesweeper

Default

It's pretty cool.
Do you have an icon that should appear in the tools overview?

I'm also considering a rewrite of Widgetizer in C++ btw.
__________________
Zoom (requires log in)
PitzerMike is offline   Reply With Quote
Old 06-22-2009, 04:52 PM   #11
Seshiro
User
 
Seshiro's Avatar
 
Join Date: Aug 2008
Posts: 158

Submissions (1)

Seshiro is on a distinguished road (20)

Default

This is why I'm going to marry you :)
this tool is so genuine :)
I use it for many things...and now I'm going to build a hero-description script to build html pages.

Greez

Are you going to add real OOP into this? :)
With methods....

Last edited by Seshiro : 06-22-2009 at 06:17 PM.
Seshiro is offline   Reply With Quote
Old 06-23-2009, 07:00 AM   #12
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

Quote:
Originally Posted by PitzerMike
It's pretty cool.
Do you have an icon that should appear in the tools overview?
Uploaded one!

Quote:
Originally Posted by PitzerMike
Are you going to add real OOP into this? :)
With methods....
If I keep port this tool for SC2 or anything else I'm considering that :). My own scripts already get big and unreadable. OOP would reduce that mess ;)


Quote:
Originally Posted by Litany
For example, Alexander244 and I were discussing dynamic tooltips about a year ago, and he worked out a great system for item socketing that would require 90 copies of each socketed item. Both this tool and the ObjectMerger can already take the base item and make those extra copies fairly easily, but too much object data will eventually cause the Widgetizer to fail, so a method to write directly to the SLKs of a post-widgetized map would be helpful. In the case of items you're probably never going to reach the Widgetizer's limit (I forget what it is; certainly fewer than 20,000 objects), but say for some reason you wanted dynamic ability manacosts and cooldowns in roughly 1% intervals up to 100% +/- the default or something. The number of objects could quickly get out of hand.
This can be done of course. The good thing is that GMSI can change the codes of your items before widgetizing them (Because I always have the problem with the customkeys.txt and messed up tooltips).
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !

Last edited by gekko : 06-23-2009 at 07:02 AM.
gekko is offline   Reply With Quote
Old 06-23-2009, 11:18 AM   #13
PitzerMike
Alcopops
 
PitzerMike's Avatar


Tools & Tutorials Moderator
 
Join Date: Jan 2003
Posts: 2,794

Submissions (12)

PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)

Approved Map: Pitzer's Minesweeper

Default

Approved then. :D
__________________
Zoom (requires log in)
PitzerMike is offline   Reply With Quote
Old 06-24-2009, 10:16 AM   #14
Sinnergy
User
 
Sinnergy's Avatar
 
Join Date: Apr 2009
Posts: 173

Sinnergy has little to show at this moment (8)

Default

i tried injecting gmsi in jass new gen pack 5c, and when i tested a demo map (im player 1 red) with a hero owned by player 1 red on the map, i cant select it, the cursor turns red, but the selection circle for the unit is yellow (an enemy which is an ally? wtf!), and when i click a unit in the map, the upkeep title updates to the owner of the unit being picked

then i tried to delete all of my jass new gen pack 5c folder (to remove gmsi in jngp), now it works fine
__________________
Current Project:
Rise of Sinnergy v1.00
Sinnergy is offline   Reply With Quote
Old 06-24-2009, 02:29 PM   #15
gekko
User
 
gekko's Avatar
 
Join Date: Nov 2007
Posts: 129

Submissions (1)

gekko will become famous soon enough (33)gekko will become famous soon enough (33)

Default

Quote:
Originally Posted by Sinnergy
i tried injecting gmsi in jass new gen pack 5c, and when i tested a demo map (im player 1 red) with a hero owned by player 1 red on the map, i cant select it, the cursor turns red, but the selection circle for the unit is yellow (an enemy which is an ally? wtf!), and when i click a unit in the map, the upkeep title updates to the owner of the unit being picked

then i tried to delete all of my jass new gen pack 5c folder (to remove gmsi in jngp), now it works fine
sorry, this can't be the GMSI injection! Everything this injection does is just adding 4 lines to the editor injection scripts that adds the menu for calling it, nothing else. This cannot create any wicked units in your map!
It must be something else in your folder.
__________________
My stuff can be found at www.eeve.org

Check out latest GMSI !

Last edited by gekko : 06-24-2009 at 02:30 PM.
gekko is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 03:13 PM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services