| 01-06-2009, 08:03 PM | #1 |
Hey, I'm currently trying to learn JASS and am currently playing around with custom functions to learn how they work. I'm trying to make a function which creates units, groups them and uses the name entered in a chat string to name the group so it can be used to kill the group. Eg. -Mut 99,killers (creates 99 units at some point on map with the group name killers) -Kut killers (kills all units in group "killers" and removes the group) Even though my main concert in this topic is mainly group labels or a good method of indexing, I've also added the reason for why I'd like such a function. I've attempted to convert part of Golem Invocation and Forest Call by Flame_Phoenix, to create units in a circle. I'm not entirely sure how to determine unit collision size let along the calculation for calculating the angle differences to make sure the units created do not collide and always create a full circle no matter the circle radius(adaptive spacing between units depending on circle size). :| ![]() Attempting to get the above result(just moved units in position by orders), however if I were to enter 99 the number of unit circles would increase to fit the number of units. Also the first circle would start earlier from the center of the position chosen and without a unit in the middle. (the red and green lines are just markers added with mspaint :p) I've yet to experiment more with the code I've attempted to use from the spell. Will test it with set group and such for now. Any help would be appreciated. I've got to go for the day, I'll be back tomorrow. Sorry about that though I've got to work tomorrow, so good night~(forgot to paste code :p, even though it is horrible atm) Functions: JASS://Early tutorial custom function function DisplayAMessage takes string message returns nothing call BJDebugMsg(message) endfunction //BJDebugMsg() is shorter :p will change to M() or something later for easier use. function MakeUnits2 takes integer a, string b returns nothing //99% of code by Flame_Phoenix local unit u // innerRadius -> The radius of the innermost circle // outerRadius -> The radius of the outmost circle local real innerRadius = 80 local real outerRadius = 80+I2R(a)*10 // x and y -> Center of circles local real x = GetCameraTargetPositionX() local real y = GetCameraTargetPositionY() local real radiusInc = (outerRadius - innerRadius) / I2R(6) local real phi = 0 local real phiInc local group g = CreateGroup() //This code is not complete, I am trying to use string b to name the group g loop exitwhen (innerRadius + 0.001 >= outerRadius) set phi = 0 set phiInc = 2*bj_PI/I2R(a) loop exitwhen (phi + 0.001 >= 2 * bj_PI) //we add the units to a group, so we can kill them when we want ! =P call GroupAddUnit(g, CreateUnit(GetTriggerPlayer(), 'hfoo', x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi))) call DisplayAMessage("Attempted to create unit "+I2S(a)) set phi = phi + phiInc endloop set innerRadius = innerRadius + radiusInc endloop set u = null endfunction //My first attempt to make units in a circle is horrible. //It made squares ... :p Code probably didn't work... function MakeUnits takes integer a returns nothing local group unt local integer L = 0 local real m = 0 local real ar = 0 local real o = 80 local location loc = GetRandomLocInRect(GetPlayableMapRect()) local location uni = loc local unit u loop exitwhen L > a set ar = m*(360/31) if ar > 360. then set o = o + 80 set m = 0. else set uni = PolarProjectionBJ(loc, o, ar) set m = m + 1. endif set L = L+1 endloop set loc = null set uni = null set u = null endfunction //Bellow is the function I've got called to use to determine how many units and such. //It has flaws and probably needs a rewrite later on, though it is only for test purpose atm. unction Trig_MyFunction_Actions takes nothing returns nothing local string tst = SubString(GetEventPlayerChatString(),1,3) local string nfo = SubString(GetEventPlayerChatString(),5,StringLength(GetEventPlayerChatString())-5) local string grp local string amt if tst == "Kut" then call DisplayAMessage("-Kut has been typed") call DisplayAMessage("Units in group "+grp+" will be killed!") if SubString(nfo,1,1) == "," then set grp = SubString(nfo,2,StringLength(nfo)-1) set amt = SubString(nfo,0,0) elseif SubString(nfo,2,2) == "," then set grp = SubString(nfo,3,StringLength(nfo)-2) set amt = SubString(nfo,0,1) endif endif if tst == "Mut" then //-Mut is letters 0 to 4 where the last space is letter 4. //xx are letters 5 to 6 where the first letter is x and the last is 6 //, can be 7,8 or 8,9. call DisplayAMessage("Units created will be in group "+grp) if SubString(nfo,1,1) == "," then set grp = SubString(nfo,2,StringLength(nfo)-1) set amt = SubString(nfo,0,0) elseif SubString(nfo,2,2) == "," then set grp = SubString(nfo,3,StringLength(nfo)-2) set amt = SubString(nfo,0,1) endif call DisplayAMessage(SubString(GetEventPlayerChatString(),5,6) + " was then declared after.") //call DisplayTextToPlayer(Player(GetPlayerId(GetTriggerPlayer())),0,0,GetEventPlayerChatString()) if S2I(SubString(GetEventPlayerChatString(),5,7)) > 0 and SubString(grp,0,0) != "," and tst == "Mut" then call MakeUnits2(S2I(amt),grp) elseif tst == "Kut" and SubString(grp,0,0) != "," then call KillUnits("ugd_" + grp) else call DisplayAMessage("Too little units or other error!") endif endif set tst = null set grp = null set nfo = null endfunction //I'm hoping I did not miss anything. Flame_Phoenix - for the Golem Invocation code hopefully not minding me snipping pieces from it :p ~bowzerbro |
| 01-06-2009, 09:54 PM | #2 |
EDIT: Fixed two stupid typos. |
| 01-06-2009, 11:58 PM | #3 |
Making units in a circle is best accomplished (at least most easily, I find) through the use of trigonometric functions in order to project coordinates from some source point. The angular offset of each unit can be determined by dividing 360 degrees or 2 pi radians by the number of units you require in the circle. Collision size generally ranges from 16 to 32 I think, and you'll be able to detect whether collision will actually kick in by calculating the radius of the circle and dividing that by the number of units. |
| 01-07-2009, 12:14 AM | #4 |
Okay, well here's some math for you. Given that you know most everything about your situation (radii, collision sizes, number of units), finding the one remaining thing, the AngleIncrement, is actually pretty easy. The basic math here is AngleIncrement = 6.28318/<Number of Units>, and then you do this: JASS:local integer N = <whatever> local real AngleIncrement = 6.28318/N local integer I = 0 loop set X = CenterX+Radius*Cos(AngleIncrement*I) set Y = CenterY+Radius*Sin(AngleIncrement*I) call CreateUnit(Player(15), 'hfoo', X, Y, AngleIncrement*I*57.2958) //Because unit facing is in degrees, not radians set I = I+1 exitwhen I >= N endloop JASS:local integer Max = R2I(R0/(C*2.00)) //multiplied by two because collision size is a radius, is it not? JASS:local integer AngleIncrement = 6.28318/Max JASS:local integer Max = R2I(R[0]/(C*2.00)) local real AngleIncrement = 6.28318/Max local integer I = 0 loop set X = CenterX+R[0]*Cos(AngleIncrement*I) set Y = CenterY+R[0]*Sin(AngleIncrement*I) call CreateUnit(Player(15), 'hfoo', X, Y, AngleIncrement*I*57.2958) set I = I+1 exitwhen I >= Max endloop JASS:local integer Count = 99 local integer J = 0 loop set Count = Count-Max if Count <= 0 then exitwhen true else set J = J+1 endif endloop JASS:local integer Count = 99 local integer J = 0 local integer Max local real AngleIncrement local integer I loop set I = 0 set Max = R2I(R[J]/(C*2.00)) set AngleIncrement = 6.28318/Max loop set X = CenterX+R[J]*Cos(AngleIncrement*I) set Y = CenterY+R[J]*Sin(AngleIncrement*I) call CreateUnit(Player(15), 'hfoo', X, Y, Angle*57.2958) set I = I+1 exitwhen I >= Max endloop set Count = Count-Max if Count <= 0 then exitwhen true else set J = J+1 endif endloop JASS:local integer Count = 99 local integer J = 0 loop set Count = Count-Max if Count <= 0 then exitwhen true else set J = J+1 endif endloop JASS:local integer Count = 99 local integer J = 0 local integer Max local real AngleIncrement local integer I loop set I = 0 set Max = R2I(R[J]/(C*2.00)) if Max > Count then set Max = Count endif set AngleIncrement = 6.28318/Max loop set X = CenterX+R[J]*Cos(AngleIncrement*I) set Y = CenterY+R[J]*Sin(AngleIncrement*I) call CreateUnit(Player(15), 'hfoo', X, Y, Angle*57.2958) set I = I+1 exitwhen I >= Max endloop set Count = Count-Max if Count <= 0 then exitwhen true else set J = J+1 endif endloop As long as you can supply R[0], R[1]...R[N] and the collision size of the units being created (which can be found with GetUnitCollisionSize()), then this should work. |
| 01-07-2009, 12:28 AM | #5 |
As for the labelling, look into gamecache. If you are using vJass, a combination of structs and Table (specifically the StringTable class), you can store the unit group based on a string. JASS:globals private StringTable string2group = null endglobals struct UnitGroupStruct group g string label static method create takes unitgroup g, string label returns UnitGroupStruct local UnitGroupStruct this = UnitGroupStruct.allocate() set this.g = g set this.label = label set string2group[label] = this // sets reference return this endmethod method onDestroy takes nothing returns nothing set string2group[this.label] = 0 // clears reference if this.g != null then call DestroyGroup(this.g) set this.g = null endif endmethod static method GetGroupFromString takes string s returns UnitGroupStruct return string2group[s] endmethod endstruct function DemoInit takes nothing returns nothing // call this function first set string2group = StringTable.create() // allocates a table to use endfunction // Then you can use: UnitGroupStruct.create(group, label) // to create a unitgroup reference set someUnitGroupStructVar = UnitGroupStruct.GetGroupFromString(label) // to get back the struct someUnitGroupStructVar.g // to access the group, and someUnitGroupStructVar.destroy() // to remove everything when done. I would recommend learning vJass as you learn Jass since it is much easier to code in and provides much more flexibility. |
| 01-07-2009, 06:45 PM | #6 | |||
Quote:
Quote:
Thanks for your reply. Quote:
I ended up with squares, indicating that they just spawned where they were able to ;p Pyrogasm: Thank you. I can understand most of the code but am not good at calculations. I used to know those things but I've never had any use for math over like +,-,* and / :p eh.. I suppose I meant, radius calculations and such. I hope I revive some knowledge throughout my jassing :) Ammorth: Good, clean and understandable reply.(not that other ones were but I thought since the system is so clean it made the code cleaner thus making reply shorter and .. yeah) Just need to implement system :) Thanks. I've got PUI on the test map but not using :p My comp is quite slow and I read it would be faster and that all systems can be used with it(if converted). I'll not bother trying to use it yet ;p But the table function is one I need to learn how to implement because I'll need to use Unit Properties on my main map. Thanks to all for your replies ![]() ~bowzerbro, will attempt to make circles of units soon! { Add: Holy pasta in random shapes, I clicked submit but it never posted. I've been cleaning and stuff and will soon go to sleep. Not gotten any time to test spawning units :| } |
| 01-11-2009, 06:01 PM | #7 |
Getting a few problems with unit group label sys. PJASS 16 compile errors [not listed all] Cannot convert null to integer * integer UnitGroupLabel__string2group= null Undefined type unitgroup * unitgroup f__arg_unitgroup1 * function sc__UnitGroupStruct_create takes unitgroup g,string label returns integer Undeclared variable string2group * set string2group = s__StringTable__allocate() // allocates a table to use I've got quite a few other errors but those are because I'm not sure how to use various functions yet and haven't specified various values. Pyrogasm: Will I have to pre-set all the R[#] radius values? Table converts a var set as R[#] to R0,R1 etc? Or do I use R[0] again to get the value in R[0]? :o I'm slightly confused due to all I've read in various topics. 1. I've read that arrays are slow. 2. I've read that gamecache sucks due to many bugs as well as being slower than available alternatives. 3. Missed or unable to find clear explanations on how to implement things. Such as knowing where to put the code if I'm not told where to, which order to place triggers with functions so they work together correctly. When to put scopes, where to put the scopes (order), which order to init new functions and so on. Syntax Check can not be trusted? It gives me a large variety of error reports such as saying that there is no function named GetUnitCollisionSize. I made a trigger named GetUnitCollisionSize and made it run on map init. Though didn't name it Init_GetUnitCollisionSize. I'm sorry, I find learning things on forums quite hard. I've made a lot of macros and scripted a lot of things for various programs. I've never really in any mayor code-language but I've read snips of quite a few languages and I've not had problems seeing how the structure worked. However I think JASS is harder due to mixing of languages, lack of proper error descriptions and not as powerful as some scripting languages even. :p I'm a bit frustrated due to lack of time to spend on trying to learn something, finding it harder to learn this than anything I've got myself into and every break rusts the progress so I'll have to spend some time to remember where I was. I'm not sure who said it but someone said "it only takes one day to learn jass", I assume that's if you had all links, knew where to start and there were simple yet understandable enough explanations for everything, had that whole days time to spend and didn't end up confusing yourself by digging too deep too early. :p I need a fresh start.. The bellow is nowhere close to complete. I'm lost in all the functions atm, quite tired. There are many values and probably some functions and such not stated. And I'm sure there's a lot not yet changed to code. JASS://Get Radius to use function GetR takes real in, real dif returns real // The value in is unitcollisionsize. dif is the difference between circles. // And value out is the radius increase to use. local integer ucs return ucs+dif //collisionsize + distance between circles. endfunction function GetColSize takes integer unt returns real local unit u set u=Unit.create(CreateUnit(Player(12), unt, 0, 0, 0)) return GetUnitCollisionSize(u) call u.destroy() endfunction function MakeUnits3 takes integer a, string grp, real ux, real uy, integer unt returns nothing local real X = ux local real Y = uy local integer Count = a local integer J = 0 local integer Max local real AngleIncrement local integer I local group ug = CreateGroup() call DemoInit() call GetColSize(unt) set ug = UnitGroupStruct.create(ug, grp) loop set I = 0 set Max = R2I(R[J]/(C*2.00)) if Max > Count then set Max = Count endif set AngleIncrement = 6.28318/Max loop set X = ux+R[J]*Cos(AngleIncrement*I) set Y = uy+R[J]*Sin(AngleIncrement*I) call GroupAddUnit(ug, CreateUnit(Player(0), 'hfoo', X, Y, Angle*57.2958)) //Was Angle a typo or unit facing, what if unit faces 0 :p? It isn't specified anywhere :X set I = I+1 exitwhen I >= Max endloop set Count = Count-Max if Count <= 0 then exitwhen true else set J = J+1 endif set ug=null endloop endfunction ~yawn~ I hope this post made some sense since right now I'm not feeling fit to code. I'm probably just going through the phrase before you go "OH! Now it all makes sense!".. :p ![]() |
| 01-12-2009, 06:51 AM | #8 |
When you get bogus errors it's because you've forgotten something silly like an endif or endfunction or something and the parser just has a field day on that and gives all sorts of errors to hell and back. If you have AIM, MSN, YIM, ICQ, or Gtalk, get my contact info from my profile and send me a message. I'm online nearly all the time (though idle for a fair amount while I'm at school), and I certainly don't have a problem talking with you in real time if that helps you learn. Anyway, regarding your script...: JASS://Get Radius to use function GetR takes real in, real dif returns real // The value in is unitcollisionsize. dif is the difference between circles. // And value out is the radius increase to use. local integer ucs return ucs+dif //collisionsize + distance between circles. endfunction JASS:function GetR takes real Previous, real UCS returns real local real Modifier = 35.00 if Modifier < UCS then return Previous+UCS endif return Previous+Modifier endfunction JASS:function GetColSize takes integer unt returns real local unit u set u=Unit.create(CreateUnit(Player(12), unt, 0, 0, 0)) return GetUnitCollisionSize(u) call u.destroy() endfunction Something it looks like you don't understand is that in JASS, everything after a return stops. After you return a value (or you can just return with no value), the next lines of code are never executed. Here, the unit will never be removed (you put .destroy() when it should be RemoveUnit(u)]) because there is a return before it: JASS:function GetColSize takes integer unt returns real local unit u=CreateUnit(Player(12), unt, 0.00, 0.00, 0.00)) local real c = GetUnitCollisionSize(u) call RemoveUnit(u) return c endfunction As for the rest, I think it might be best to start over entirely whilst writing all the code yourself. It's a bit of a mess because you combined my code and yours and you have a lot of extra fluff/nonsensical stuff. Also, I don't have time to go over that part right now, but perhaps in the near future I will. Contact me online if you'd like, I'm GMT -8:00. |
| 01-12-2009, 09:04 PM | #9 | |
Quote:
Anyway, I suppose we may be able to speak on.. hmm darn. Maybe next weekend or if I'm ever home early or something. I am GTM so quite hard to find time :p Thanks for reply, now I'm off to bed. Will attempt waking up at 5 am to get to work early :p ... May end up waiting liek an hour for trains in denmark to start going :p Good night ~bowzerbro Bellow would never work :p JASS:if not GetPlayerEnteredChat() == "" then case "Help" call CustomAIAssistFunction(GetTriggerPlayer()) case "Attack!" call CustumAIAttackFunction(GetTriggerPlayer()) case "Retreat!" call CustomAIRetreatFunction(GetTriggerPlayer()) case "Hold position" call CustomAIHaltFunction(GetTriggerPlayer()) case "Deffend position" call CustomAIDeffendPosFunction(GetTriggerPlayer()) case "Fight among each other!" call CustomAIChaosFunction(GetTriggerPlayer()) case "Archers target " call CaseSub(GetSubString(GetPlayerEnteredChat(),16,StringLength(<entered string>-16))) else call CalledUnitSay("Now, there isn't any such command! Type -AIHelp for a list of squad commands.") endif JASS:function CaseSub takes string x returns nothing if not x == "" case "weakest" call CustomAIAAWeakFunc(GetTriggerPlayer()) case "strongest" call CustomAIAAStrongFunc(GetTriggerPlayer()) case "structures" call CustomAIAAStrucFunc(GetTriggerPlayer()) case "hero" call CustomAIAAHeroFunc(GetTriggerPlayer()) else call CalledUnitSay("Huh? What master?") //Would make archer squad leader say "<this>" endif endfunction |
| 01-12-2009, 11:54 PM | #10 |
What you're looking for is elseif. JASS:local string s = GetEventPlayerChatString() if s == "" then call CalledUnitSay("Now, there isn't any such command! Type -AIHelp for a list of squad commands.") elseif s == "Help" call CustomAIAssistFunction(GetTriggerPlayer()) elseif s == "Attack!" call CustumAIAttackFunction(GetTriggerPlayer()) elseif s == "Retreat!" call CustomAIRetreatFunction(GetTriggerPlayer()) elseif s == "Hold position" call CustomAIHaltFunction(GetTriggerPlayer()) elseif s == "Deffend position" call CustomAIDeffendPosFunction(GetTriggerPlayer()) elseif s == "Fight among each other!" call CustomAIChaosFunction(GetTriggerPlayer()) elseif s == "Archers target " call CaseSub(GetSubString(GetPlayerEnteredChat(),16,StringLength(<entered string>-16))) endif |
| 01-13-2009, 04:50 PM | #11 | |
Quote:
Repeated patterns can be easier and harder to find bugs in depending on size. Will continue trying to figure out a few things about how unit identification works. I'm stuck in an example map trying to make a unit respawn if it dies. I've tried so many combinations and none has worked. JASS:return IsUnitIdType( 'nrwm', ConvertUnitType(GetUnitTypeId(GetTriggerUnit())) ) == true I want a function that auto-chooses the right conversion method to use :| Probably not possible since functions has to take <vartype> <var> and can't just take <var> then do if comparing to get <vartype>, eg. JASS://THIS IS THEORETICAL JASS!!! call IsUnitAuto('nrwm',DeadUnit()) function IsUnitAuto takes 1,2 returns boolean if GetType(1) == unit then if GetType(2) == unit then IsUnitType(1,2) == true endif elseif GetType(1) == unittype then //And so on, probably using some other method which is cleaner. endfunction |
| 01-13-2009, 05:31 PM | #12 |
Can't you just do return IsUnitTypeId(GetTriggerUnit())=='nrwm' |
| 01-14-2009, 06:57 PM | #13 | |
Note: This ended up being quite diff from intended. (topic that is) However, note that one can see the entire post progress in here as my road towards being able to use label system? ;p .. Quote:
I'm not sure I may be using that now :p I got it working somehow. I believe I converted into strings and then used the strings. Even though another map has the exact string it doesn't work for that mob for some reason. Anyway, I'm trying to make mobs respawn as higher level when hero is higher than them but doesn't seem to work. I can set max hp and mana :p Would have to use abilities to make them stronger. My current wacky code :: JASS://there was a lot of messy code here, due to serious update it got removedI assume I'd need to use unit properties and stuff to make them level up. Could probably use custom value and abilities and then use some calculation to make these abilities be added and lvld in a way so they do not quickly make the monsters imba :p ... Anyway I've got like 30 min to spend before I go sleep. Getting up at 5am tomorrow and want to work to like 10 pm :p So wont be here tomorrow. Good night ![]() Good night again.. The code above is flawed, I uploaded map instead. :) |
