Announcement

Collapse
No announcement yet.

Getting Started With SLIC

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Events-based Scripting in CtP2 (part 2)

    5.0 - Functions

    Function reference - http://apolyton.net/ctp2/modificatio...lic2func.shtml

    Functions come in two types, as, I beleive they do in C. Integer functions (int_f) return a number, and void functions (void_f) don't return anything, they just execute some action.
    I think in essence, with SLIC as a way to code reactions to events, the void_f functios will be the reaction, and the int_f functions will be a way of narrowing down where the reaction occurs.

    5.1 - Code with Functions In

    In reality, it is nearly impossible to code anything without using functions, but some code is more based on functions than others.
    Going back to this example:
    Code:
    HandleEvent(MoveUnits) 'kill_the_unit' pre {
    	unit_t tmpUnit;							// define variable
    	tmpUnit = unit[0];						// define what it actually is
    	player[0] = unit[0].owner;					// name the unit's owner (it is not implicit in the event)
    	if(player[0].cities > 10){					// if statement. IF the unit's owner has 10 cities...
    		KillUnit(tmpUnit);					// if 'yes', then do function. Kill the unit.
    	}								// close if statement
    	elseif(player[0].cities < 3){					// ELSEIF the unit's owner has less than 3 cities...
    		KillUnit(tmpUnit);					// if 'yes', then do function. Kill the unit.
    		int_t	i;						// define counter variable
    		for(i = 0; i < player[0].cities; i = i + 1){		// for each of player[0]'s cities...
    			city_t	tmpCity;			// define
    			GetCityByIndex(player[0], i, tmpCity);		// Find the city currently being dealt with
    
    			if(CityHasBuilding(tmpCity, BuildingDB(IMPROVE_SILO))){		// if city has silo
    
    				AddGold(player[0], 5000);		// give 5000 compensation 
    			}
    			elseif(CityHasBulding(tmpCity, BuildingDB(IMPROVE_GRANARY))){	// otherwise if it has a granary
    				
    				AddGold(player[0], 3000);		// give 3000 gold
    			}
    			else {
    				AddGold(player[0], 1000);		// otherwise, give just 1000
    			}
    		}							// close for loop
    	}								// close elseif statement
    	else{								// ELSE. (none of the above)...
    		Heal(tmpUnit);						// if its still there, then heal the unit.
    	}								// close else loop
    }									// close handler
    In the emboldened section are the functions GetCityByIndex, CityHasBuilding and AddGold.
    GetCityByIndex and AddGold are void_f functions, they do not return any integers, they just react.

    AddGold is a simple action function, it adds gold to the player's treasury.

    GetCityByIndex is more complicated, though it doesn't return a number, it doesn't act as such. What it does is return a city, in the form of a variable defined beforehand, in this case tmpCity. tmpCity can now be used inside the for loop to act on that city, (after the for loop, it will only apply to the last city found in the for loop (ie when i = player[0].cities - 1).

    CityHasBuilding is an int_f function, so is usually used in a if statement. IF(CityHasBuilding(tmpCity, BuildingDB(IMPROVE_GRANARY))) THEN { do something. IF it doesn't have that building, then that reaction does not apply in this case. The int_f has limited the number of cases where the reaction applies, as carried out by the void_f function AddGold.

    5.2 - Nested Functions

    It is possible to use functions inside other functions to save the trouble of defining and using variables all the time.
    eg.
    Code:
    city_t	tmpCity;
    GetCityByIndex(player[0], random(PlayerCityCount(player[0])), tmpCity);
    This will get a city belonging to player[0] with a random index number. The random number is chosen from between 0 and player[0]'s amount of cities, so will always return a valid city. The city is then stored as tmpCity.
    This saved the bother of storing PlayerCityCount(player[0]) as a variable, then finding random(player[0].cities) and storing that, and then plugging that into the GetCity... function.

    5.3 - User-made Functions

    As well as the built-in functions, SLIC allows you to define your own functions and use them in handlers. These had me really confused at the start, as I could see loads of code with no event to trigger it, and then functions in handlers which were not listed. A good example of a custom function is Dale GetNearestCity function.

    Code:
    int_f GetDistanceNearestCity(location_t theLoc, int_t thePlayer) {	
    				// this is an int_f function needing an input of location and player
    				// definitions cut for space...
    			
    	tmpPlayer = thePlayer;
    	tmpLoc = theLoc;
    	min = 10000;
    	city = 0;				
    	cities = Cities(tmpPlayer);
    
    	for(i = 0; i < cities; i = i + 1) {
    		GetCityByIndex(tmpPlayer, i, tmpCity);
    		val = SquaredDistance(tmpCity.location, tmpLoc);
    		if(val < min) {
    			min = val;
    			city = i;
    		}
    	}
    	return city;					// this is the integer that the function returns at the end. 
    }							// It is the index of thePlayer's closest city.
    This function is used inside the main Withdraw script handler to find the nearest city that the aeroplane should return to.
    Inside a handler, the title of the fnction becomes a function, so putting it into the example handler from above:
    Code:
    HandleEvent(MoveUnits) 'kill_the_unit' pre {
    	unit_t tmpUnit;							
    	tmpUnit = unit[0];						
    	player[0] = unit[0].owner;					
    	if(player[0].cities > 10){					
    		KillUnit(tmpUnit);					
    	}								
    	elseif(player[0].cities < 3){					
    		KillUnit(tmpUnit);					
    		int_t	i;						
    		for(i = 0; i < player[0].cities; i = i + 1){		
    			city_t	tmpCity;			
    			GetCityByIndex(player[0], i, tmpCity);		
    			if(CityHasBuilding(tmpCity, BuildingDB(IMPROVE_SILO))){		
    				AddGold(player[0], 5000);		
    			}
    			else {
    				AddGold(player[0], 1000);		
    			}
    		}								// Once all cities have been done..
    		int_t	tmpIndex;
    		tmpIndex = GetNearestCity(unit[0].location, player[0]);		// find the nearest home city to the unit
    		GetCityByIndex(player[0], tmpIndex, tmpCity);			// store that city
    		CreateUnit(player[0], unit[0].type, tmpCity.location, 0);	// create a unit of the same type there
    	}								
    	else{								
    		Heal(tmpUnit);						
    	}								
    }
    That is an example of using a new function as a time and space saving device inside a handler. Often the function will be a small part of the code that is primarily the reaction to the event.
    Occassionally though, the function is more important, and the handlers are needed only to trigger it at certain times.

    5.4 - Function-Based Code
    One of the simplest example of this type of code is Locutus Capitol Code for the MedMod.
    He uses a function to rebuild a capitol, and the handlers merely as triggers to run the function.
    Code:
    // function that actually finds a replacement city for the capital and makes it build a new one
    int_f MM2_CreateCapital(int_t thePlayer) {
    city_t	tmpCity;
    city_t	largestCity;
    int_t	i;
    int_t	size;
    int_t	tmpPlayer;
    	tmpPlayer = thePlayer;
    	player[0] = tmpPlayer;
    
    	if (player[0].cities > 1) {				// if player has more cities
    		size = -1;
    		for (i = 0; i < player[3].cities; i = i + 1) {	// cycle through all cities
    			GetCityByIndex(tmpPlayer, 0, tmpCity);
    			if (tmpCity.population > size && !CityHasBuilding(tmpCity, "IMPROVE_CAPITOL")) {
    			// check for capitol needed since this is executed pre capture, so old capital is evaluated as well
    				if (IsWonderAtHead(tmpCity) == -1) {
    				// check for wonder at head of build queue is needed since ClearBuildQueue doesn't clear queues with wonders at head
    					largestCity = tmpCity;	// store city
    					size = largestCity.population;
    				}
    			}
    		}
    		if (size > -1) {				// if a city was found
    			ClearBuildQueue(largestCity);		// clear existing buildqueue
    			AddBuildingToBuildList(largestCity, BuildingDB(IMPROVE_CAPITOL));	// start building a Capitol
    			Event:BuyFront(largestCity);		// (try to) rush buy it
    		}
    	}
    }
    and the handlers that fire it when a capitol is destroyed:
    Code:
    // detect the capture of a Capital and call CreateCapital function
    HandleEvent(CaptureCity) 'MM2_CapitalCaptured' pre {
    int_t	tmpPlayer;
    city_t	tmpCity;
    	tmpCity = city[0];
    	tmpPlayer = tmpCity.owner;
    	player[3] = tmpPlayer;
    
    	if (CityHasBuilding(tmpCity, "IMPROVE_CAPITOL")) {	// if city is capital/has capitol
    		if (!IsHumanPlayer(tmpPlayer)) {		// if player isn't human
    			MM2_CreateCapital(tmpPlayer);		// find new capital
    		}
    	}
    }
    
    //ditto for KillCity event, GiveCity event, DisbandCity event, and CreatePark event.
    Using functions separate from the main code means that the code is only written out once, rather than once for each event. This makes the file shorter, easier to manage and debug, and not as spacious for uploading or downloading.

    5.5 - Events as Functions

    As well as using events to trigger reaction code, events can be forced to happen, just as functions can cause things to happen.
    eg. Taken a bit from example handler.
    Code:
    int_t	tmpIndex;
    	tmpIndex = GetNearestCity(unit[0].location, player[0]);		// find the nearest home city to the unit
    	GetCityByIndex(player[0], tmpIndex, tmpCity);			// store that city
    	CreateUnit(player[0], unit[0].type, tmpCity.location, 0, tmpUnit);	// create tmpUnit of the same type there.
    	Event:EntrenchUnit(tmpUnit);						// Use entrench event to fortify it.
    This forces the game to recognise that the fortify event has happened, as if someone pressed the F button.
    Most events in the events listing can be used like this. The ones that can't are the ones where one of the variables has a GEA_ prefix in the list. These variables are paths, and are too complicated to define in SLIC. (http://apolyton.net/ctp2/modificatio...icevents.shtml)


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~

    6.0 MessageBoxes

    Messageboxes come in two forms. Mesageboxes and alertboxes. Messageboxes can be left open, while the game continues around them. Alertboxes force play to be stopped until you have responded to them.
    A typical messagebox in SLIC looks like this:
    Code:
    messagebox 'kill_unit_or_not' {			// definition messagebox, name, open bracket
    
    	Show();				// otherwise it wouldn't show
    	Title(ID_TITLE);		// message title
    	Text(ID_TEXT);			// message text
    
    	Button(ID_YES){			// button
    		Kill();			// effect button has. Kills text box
    		KillUnit(unit[0])	// kills the unit	
    	}				// end button effect
    
    	Button(ID_NO){			// other button
    		Kill();			// only kills the text box
    	}				// end button effect
    
    }					// close
    Alertboxes are exactly the same as messageboxes, except instead of having the word messagebox where it is bold, have the word alertbox.

    Title, text and button text should be stored in scen_str.txt in ctp2_data/language/gamedata directory (Without the ID_ prefix, that is just to show the SLIC what it is)

    To make a message appear, use the message function in the handler.
    Code:
    HandleEvent(MoveUnits) 'kill_the_unit' pre {
    	unit_t tmpUnit;							
    	tmpUnit = unit[0];						
    	player[0] = unit[0].owner;					
    	if(player[0].cities > 10){					
    		KillUnit(tmpUnit);					
    	}								
    	elseif(player[0].cities < 3){					
    		KillUnit(tmpUnit);					
    		int_t	i;						
    		for(i = 0; i < player[0].cities; i = i + 1){		
    			city_t	tmpCity;			
    			GetCityByIndex(player[0], i, tmpCity);		
    			if(CityHasBuilding(tmpCity, BuildingDB(IMPROVE_SILO))){		
    				AddGold(player[0], 5000);		
    			}
    			else {
    				AddGold(player[0], 1000);		
    			}
    		}								// Once all cities have been done..
    		int_t	tmpIndex;
    		tmpIndex = GetNearestCity(unit[0].location, player[0]);		// find the nearest home city to the unit
    		GetCityByIndex(player[0], tmpIndex, tmpCity);			// store that city
    		CreateUnit(player[0], unit[0].type, tmpCity.location, 0);	// create a unit of the same type there
    	}								
    	else{								
    		message(player[0], 'kill_unit_or_not');			// give a choice whether or not to kill it						
    	}								
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~

    7.0 Mod_ functions

    The wierdest of all SLIC, these are functions that do not have to be triggered, but apply all the time in the game. There are theoretically eight, but only four have obvious effects. These are:

    Code:
    int_f mod_CanPlayerHaveAdvance(int_t thePlayer, int_t theAdvance)
    {
    Code:
    int_f mod_CanCityBuildBuilding(city_t theCity, int_t theBuilding)
    {
    Code:
    int_f mod_CanCityBuildUnit(city_t theCity, int_t theUnit)
    {
    Code:
    int_f mod_CanCityBuildWonder(city_t theCity, int_t theWonder)
    {
    They do exactly as they suggest, they limit which techs, wonders, buildings and units are available to players and cities.
    You can use code (mostly if statements I should think) to limit to where the rules apply. If in doubt, copy a known format. The Alexander the Great scenario has a basic example of limitations to a tech tree, and the MedMod2 restricts the use of some units. I think the only place that uses the mod_CanCityBuildBuilding function is my Mars 2020 scenario (currently in beta testing), so here is the code for that.

    Code:
    int_f mod_CanCityBuildBuilding(city_t theCity, int_t theBuilding)
    {
    	
    	int_t	tmpBuilding;
    	tmpBuilding = theBuilding;
    	tmpCity = theCity;
    	city[0] = tmpCity;
    	if(tmpBuilding == BuildingDB(IMPROVE_SOLAR_PLANT)){
    		if(g.year >= 48){
    			return 1;
    		}
    		else {
    			return 0;
    		}
    	} elseif(tmpBuilding == BuildingDB(IMPROVE_HOSPITAL) || tmpBuilding == BuildingDB(IMPROVE_PUBLISHING_HOUSE)) {
    		if(G.YEAR >= 36){
    			return 1;
    		}
    		else {
    			return 0;
    		} 
    	} elseif(tmpBuilding == BuildingDB(IMPROVE_ORBITAL_LABORATORY) ) {
    		if(G.YEAR >= 24){
    			return 1;
    		}
    		else {
    			return 0;
    		}
    	} elseif(tmpBuilding == BuildingDB(IMPROVE_ACADEMY)){
    		if(g.year >= 12){
    			return 1;
    		}
    		else {
    			return 0;
    		}
    	} elseif(tmpBuilding == BuildingDB(IMPROVE_AQUEDUCT)){
    		tmpNum = city[0].population;
    		if(tmpNum >= 3){
    			return 1;
    		}
    		else {
    			return 0;
    		}
    	} elseif(tmpBuilding == BuildingDB(IMPROVE_COMPUTER_CENTER)){
    		tmpNum = city[0].population;
    		if(tmpNum >= 3 && g.year >= 6){
    			return 1;
    		}
    		else {
    			return 0;
    		}
    	} else {
    		return 1;
    	}
    }
    Start with deciding which building you want to limit the use of, then decide who you are limiting the building to or from, and why.

    If anyone wants to experiment with the other four, they are:
    Code:
    mod_CityHappiness
    mod_UnitAttack
    mod_UnitRangedAttack
    mod_UnitDefense
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~

    8.0 End Note

    As I said at the beginning, this is not necessarily a good way to learn SLIC, but it is in theory the way I learned. In actuality, I learned by doing. Hack as much code from other places as you can. Some of the functions are buggy, some don't work, some have limitations. Read around the Apolyton Mods forum right back to the beginning, and download everything you can. (If you can understand BlueO's city expansion then you're there!) Read as much SLIC as you can, and try to figure out why their code works. If your's doesn't, try for a workaround, model your code on other people's, and start a help thread in the forum, we the SLICers will help, 'cos we all had difficulties to start with.

    So...
    Before you code, have a method
    Work though the method, be flexible, and willing to mix methods to get a result.
    The best debugger is the game itself. Put DebugSlic to Yes in userprofile.txt to get rid of errors.
    Alt-Tab out, fix the bug, and /reloadslic. Repeat ad nauseum
    When it goes right, no matter how clumsy it looks in relation to other code, its a great feeling
    And have fun!

    Ben Weaver (aka The Immortal Wombat)
    24/11/01

    attachment is a text version of this, with vB and HTML tags included.
    Attached Files
    Concrete, Abstract, or Squoingy?
    "I don't believe in giving scripting languages because the only additional power they give users is the power to create bugs." - Mike Breitkreutz, Firaxis

    Comment


    • #17
      Well look at that, EditPlus' window can fit more character in it that the thread page can. Sorry about the long lines
      Concrete, Abstract, or Squoingy?
      "I don't believe in giving scripting languages because the only additional power they give users is the power to create bugs." - Mike Breitkreutz, Firaxis

      Comment


      • #18
        *bump*

        Comment


        • #19
          1.) is CtP2 just an upgrade for CtP, that is can i upgrade it with a patch. i couldnt find that info anywhere.

          2.) what changes are there from CtP to CtP2 ? any links regarding that. im only running in circles right now.

          3.) arent there any MP or PbEM games for CtP 1 ?

          4.) this SLIC thing, will that help with PbEM games ?
          Baal: "You dare mock me ?"
          O'Neill: "Baal, c'mon, you should know ... Of course I dare mock you."

          Comment


          • #20
            5.) oh and why arent the posts sorted chronologicalls like in any other forum ?
            Baal: "You dare mock me ?"
            O'Neill: "Baal, c'mon, you should know ... Of course I dare mock you."

            Comment


            • #21
              1) no a totally new game you gotta buy. Theres is some info in here:

              but i dont know if they will match with you are looking for

              2) big changes wait to someone to explain i really dont have time. But as i said a totally new game.

              3) MP yes, PBEM yes but there is no human-human diplomacy. Yet i am the one working to fix this. and i think i will be done in less than a week.

              4) As i said i am fixing it through slic

              5) they are!!! Just that some threads are toped so they dont drop. In this forum there is only one but in the other CTP2 forum you got plenty of it (Shouldnt we drop some, Locutus?) what make thing a bit confusing. If the not only the topped threads arent chronolocally i think you gotta a problem.
              "Kill a man and you are a murder.
              Kill thousands and you are a conquer.
              Kill all and you are a God!"
              -Jean Rostand

              Comment


              • #22
                I think we should make the sticky threads more distiguishable eg Make them all a different font Red or something. Cause there have been quite a few problems with ppl who dont visit here much or newbies (hate that word) thinking that the forum hasnt been posted in for ages.
                Oxygen should be considered a drug
                Tiberian Sun Retro
                My Mod for Tiberian Sun Webmaster of
                http://www.tiberiumsun.com

                Comment


                • #23
                  Pedrunn, 3) was about CtP1.

                  Mathemagician, the CtP1 MP forum is here

                  re: 2) There should be an online manual somewhere which details changes.
                  Concrete, Abstract, or Squoingy?
                  "I don't believe in giving scripting languages because the only additional power they give users is the power to create bugs." - Mike Breitkreutz, Firaxis

                  Comment


                  • #24
                    Ooops. Sorry i read it to fast.
                    "Kill a man and you are a murder.
                    Kill thousands and you are a conquer.
                    Kill all and you are a God!"
                    -Jean Rostand

                    Comment


                    • #25
                      Originally posted by Pedrunn
                      (Shouldnt we drop some, Locutus?)
                      Which ones? I hate to have more than 3 topped threads, but at present they're all needed The MP Tourney thread will eventually go but the FAQ, SP Tournament, Screenshot, MP Registry must all stay. Mod Wrapup can go but something else will need to replace it: a quick guide that will explain what newbies need to know: where to download, what kinds of play are available and what is needed for them, what mods there are and what differences between them, etc...

                      Mathemagician,
                      There *are* MP Games for CtP2. In fact, an official Apolyton MP Tournament is starting this Saturday!

                      As far as differences between CtP1 and CtP2: in large outlines the games are the same, but there are many differences. CtP2 is by no means a complete overhaul, but it *is* a different game. Armies can now be 12 units large, you can retreat from battle, armor and firepower were introduced, flanking combat, there's a different trade system, no more space layer (it was buggy and unbalancing), MAD (nuclear warfare different), feats of wonders, mayors, resource collection has been overhauled, unconventional warface changed, the deep water concept changed, the interface is completely different, borders were introduced, city radii are now variable, diplomacy is different, the scientific endgame is competely different, there are new units/wonders/improvements/etc, etc, etc. Read the Info section if you want to know more.
                      Administrator of WePlayCiv -- Civ5 Info Centre | Forum | Gallery

                      Comment


                      • #26
                        At least would it be possible to move the information from the Mod WrapUp to the CTP2 page?

                        -Martin
                        Civ2 military advisor: "No complaints, Sir!"

                        Comment


                        • #27
                          No, it's obsolete, it needs to be updated first. I could move the info that was to be in the new thread there - not a bad idea - but even then I'll have to compile the stuff in the forums and discuss the issue with Dan and Markos first.
                          Administrator of WePlayCiv -- Civ5 Info Centre | Forum | Gallery

                          Comment


                          • #28
                            How do i disable the creation of .bak files when saving files with editplus ?

                            How can i make txt files to be open with editplus and not the notepad as in the windows default ? (I use win98)

                            Locutus you should clean up this thread and top it. Some really important info here
                            "Kill a man and you are a murder.
                            Kill thousands and you are a conquer.
                            Kill all and you are a God!"
                            -Jean Rostand

                            Comment


                            • #29
                              How do i disable the creation of .bak files when saving files with editplus ?
                              Lol i found this annoying to when I was adding ur barb.slc to every cradle script. But sorry I cant help you here sure IW or someone can though..

                              How can i make txt files to be open with editplus and not the notepad as in the windows default ? (I use win98)
                              Ahh win98 Hold shift and right click on the particular .slc or whatever it is ur opening. In ther menu there now should be an option "Open With" choose ur program (EditPlus) and tick the check box at the bottom saying something like "Always open with". Of course if the prog isnt in the list browse

                              Locutus you should clean up this thread and top it. Some really important info here
                              I agree


                              P.S. Pedrunn
                              where those space terrians for your Space scenario of any use ?? and if so are u going to use the big planet/stars that take up like 4 sqares??
                              Oxygen should be considered a drug
                              Tiberian Sun Retro
                              My Mod for Tiberian Sun Webmaster of
                              http://www.tiberiumsun.com

                              Comment


                              • #30
                                Couple of questions:

                                1) How many tile improvement layers are there? It appears there are 2 can I have 3?

                                2) I've been eyeing up these .ldl files. Is it possible to create our own and link them to SLIC. I basically want sliders.

                                3) I didn't see a way to forcibly modify city growth rates. Or change food..etc. Is that possible or is it only gold we can modify?

                                4) Is there a limit to the number of terrains and tile improvements in the game?

                                Any help would be much appreciated.

                                Comment

                                Working...
                                X