Click.mac v3.00b - resurrect corpses (new version, OMG!)

Post your completed (working) macros here. Only for macros using MQ2Data syntax!

Moderator: MacroQuest Developers

User avatar
blueninja
a grimling bloodguard
a grimling bloodguard
Posts: 541
Joined: Thu Aug 28, 2003 7:03 am
Location: Göteborg, Sweden

Click.mac v3.00b - resurrect corpses (new version, OMG!)

Post by blueninja » Sun Feb 19, 2006 4:32 pm

Resurrects corpses in an area around you, sorted according to a certain order defined in the ini-file. Designed mainly for the raiding cleric to assist in resurrecting after or during raid encounters although it would techically work for a paladin or non-raiding cleric as well. It works inside a specified radius around you and checks corpses for valid timers by consenting them. The sorting mechanism is useful for example if you want to give precedence to classes vital to quickly getting the raid back on it's feet or surviving an encounter in a bad shape. It can also prioritize friends or ignore people or guilds you dislike.

This is the third major version of my macro that resurrects corpses in an area around you for clerics and paladins. I know it's long over due, the old one was forgotten as my previous guild fell apart (damn those ban-happy GMs :). Now that my current guild has started working on OMM and spider queen there has been plenty of need for a macro like this. I was reminded of this old project and decided to get to work.

It is a complete rewrite from the previous version. Some features are:
  • Ability to swap in epic automatically*
  • Automatic detection of epic and highest availiable resurrection spell*
  • Skipping corpses acknowledged by other clerics through hails or custom messages*
  • Skipping corpses whose owners are already looting*
  • Consents to determine if a corpse is valid
  • A more advanced method of defining the order in which to rez corpses*
  • Ability to ignore corpses definable through the sort ruleset
  • Possibility to define several rulesets and choose among them on the command line
  • Accurate separation of player and npc corpses*
  • Tells to the recipient and to a channel of your choice as you rez as well as hailing the corpse*
  • Several features to help hide the fact that you use a macro to rez*
  • A special guild lobby mode that only resurrects corpses when their owner is close (only active in GL)*
    * improvement over version 2.x

Paranoia features (for those who don't want to look like rez-machines):
These are all disabled by default and controlled from the ini-file.
  • Line of sight check to corpses
  • Random time delays between resurrections
  • Randomizable resurrection order (random type in sort rules)
  • Random notifications to channels (only announce x% of resurrections)
Uses Rusty's spell_routines.inc for casting and swapping items. You can download it here:
Enhanced vip version by A_Druid_00
Original non-vip version
Quicksort routine courtesy of s0rcier.

To use follow these steps:
  • Copy and paste the three files click.mac, click_event.inc and click.ini and save them in your macro directory
  • Make sure you have spell_routines.inc installed. If not use the link provided above
  • (optional) Glance over the settings in the ini file. Defaults are usually ok but you might want to customize.
  • (optional) Customize message events in click_event.inc to capture resurrection notifications from other clerics.
  • Type "/macro click" to run.
Questions, suggestions, bug reports, etc welcome.

EDIT: 500 posts, hooray!

click_event.inc:

Code: Select all

#event Hail "#1# says, 'Hail, #2#'s corpse'"

| Edit these as needed
#event Hail "#1# tells clericchan:#*#, 'rezzing < #2# >'"
#event Hail "#1# tells clericchan:#*#, 'inc rez #2#'"
#event Hail "#1# tells clericchan:#*#, 'Rezzing - #2#'"
#event Hail "#1# tells #*#:#*#, 'Rezzing #2#'"
click.ini:

Code: Select all

[Main]
| How much output the macro should produce. 0-4 where 0 is silent, 4 is max.
NoiseLevel=3

| The radius around you to check for corpses.
Radius=200

| The vertical radius around you to check for corpses. Useful so you wont rez
| corpses on a floor below you for example.
ZRadius=50

| Check for line of sight before resurrecting a corpse. 0 to turn it off, 1 to turn it on.
LineOfSight=0

| Use special code in guild lobby. Only resurrect corpses whose owners are near them. 0 off, 1 on.
Lobby=1


| Toggles the sending of a tell to the owner of the corpse. 0 to turn it off, 1 to turn it on.
SendTell=0
| The message sent as a tell to the owner of the corpse you are resurrecting.
Tell=Inc Rez!


| Hail corpses before resurrecting them? 0 to turn it off, 1 to turn it on.
AnnounceHail=0

| Announce resurrects to a channel? Give the number of the channel here.
| This string is used in the command like this: "/<AnnounceChan> Rez inc %t !"
| Examples:
| 4 - (tell channel 4)
| g - (tell the group)
| say - (send to /say)
AnnounceChan=3

| Percentage of the time to announce resurrects to the channel. 0 to disable, 100 to announce
| everyo corpse. Useful to hide the speed at which you resurrect if you want to look less
| like a macro.
AnnouncePct=0
| Message to send to announce resurrects.
AnnounceMsg=Rez inc %t !

| Waits for a random amount of time from zero to this value between every corpse. In 1/10ths of a
| second. Useful to hide the fact that you cheat.
RandomDelay=0

| The spell gem to memorize rez spell in if epic isn't found.
SpellGem=8


[Weights]
| This section describes the order in which to sort corpses.
| Each corpse is tested against all these rules, scores are added together and the highest
| scoring corpses are rezzed first. Corpses scoring below zero (or minimumweight set on the
| command line) are ignored.
| It is possible to have more than one weight section and specify which one to use on the
| command line.
|
| The format is:
| name=[!]type|weight|matchstring
|
| Where:
| name - just a name, what it is is not important (needs to be unique in each section)
| !    - negation operator. Will reverse the current match.
| type - which type of match, valid ones are:
|        name - match character's name
|        class - match character's class                
|        guild - match the character's guild
|        inraid - matches if the character is in your raid
|        ingroup - matches if the character is in your group
|        random - will match randomly to help hide the fact that you are a cheater. The matchstring
|                 is a percentage chance to match. 0-100.
|        everyone - will be added to all corpse's scores.
| weight - the value added to the corpse's score if the rule matches
| matchstring - the search string to match (for example the name of the class or name of the character
|               when doing class or name matches respectively). Leave empty for the inraid and ingroup
|               types.


| class type: add 15 points to a corpse belonging to a bard or a cleric because they
|             will help you rez others and give you manasong!
Class1=class|15|cleric
Class2=class|15|bard

| name type: add 10 points to your friends 'mybuddy' and 'nicejoe'
Friend1=name|10|mybuddy
Friend2=name|10|nicejoe

| ingroup type: add 5 points to people in your group
group=ingroup|5|

| inraid type: add 3 points to people in your raid
raid=inraid|3|

| guild type: add 1 point to people in your guild and subtract 1 point from everyone not in it.
guild1=guild|1|my awesome guild
guild2=!guild|-1|my awesome guild

| random type: randomly add 10 points to 20% of the corpses to make you look more human
percent=random|10|20

| negative weights. Corpses with scores that fall below 0 will be ignored. Useful mainly to "blacklist"
| people or guilds. Here we give -100 points to anyone in the guild 'guildthatsucks' and that bastard
| named 'nastyjoe'. No rez for you!
badguild=guild|-100|guildthatsucks
badguy=name|-100|nastyjoe


[Dps]
| This is an example of an additional rule section for corpse rez order.
| We will use it to only rez certain classes (useful if you're desperate for dps classes during
| a fight gone bad for example).

| everyone type: subtract 1 point from every corpse so that they will be negative. Corpses
| below 0 will be skipped.
All=everyone|-1|

| class type: add points to certain classes to bring them above the 0 threshold.
Rule1=class|10|rogue
Rule2=class|10|ranger
Rule3=class|10|necromancer
Rule4=class|10|berserker
Rule5=class|10|monk
Last edited by blueninja on Mon Feb 20, 2006 9:48 am, edited 6 times in total.

User avatar
blueninja
a grimling bloodguard
a grimling bloodguard
Posts: 541
Joined: Thu Aug 28, 2003 7:03 am
Location: Göteborg, Sweden

Post by blueninja » Sun Feb 19, 2006 4:34 pm

click.mac:

Code: Select all

| Click.mac v3.00b - Ressurrect corpses around you using cleric epic or spells
|                    by blueninja
|
| Features:
| Automatically ressurects corpses with in a specified radius around you. Chooses epic or appropriate
| spell automatically. Optionally consents corpses before rez to determine if the timer has expired.
| The order in which corpses are resurrected is determined by a set of rules determined in the
| ini file with a possibility to entirely avoid certain corpses. The availiable sort criteria are
| name, class, guild, ingroup, inraid, everyone and random.
| Swaps epic in and out automatically using Rusty's spell_routines.inc.
| Skips corpses whose owner is already looting it. Skips corpses acknowledged by other clerics (using
| hails or configurable phrases).
| Configurable messages sent to the owner of the corpse and configurable channel.
| Special guildlobby mode, only resurrect corpses whose owner is near them.
|
| Stealth features:
| Configurable random time delay between rezzes.
| Possibility to change the percentage of rez announcements (don't announce every corpse to hide
| how fast you are able to rez).
| Line of sight check, you can opt to only resurrect corpses that are visible to you.
| Random weight, allows you to randomly bypass the predefined sort order.
|
| Requirements:
| A cleric or paladin.
| Rusty's spell_routines.inc, found here:
| http://www.macroquest2.com/phpBB2/viewtopic.php?t=11656 (enhanced vip version by A_Druid_00)
| http://www.macroquest2.com/phpBB2/viewtopic.php?t=7568 (original non-vip version)
| A pile of dead people.
|
| Usage:
| click.mac [rad <radius>] [zradius <zradius>] [los/nolos] [ws <weightset>]
|           [mw <minimumweight>] [lobby/nolobby]
|           rad <radius>        - sets the radius around in which to look for corpses
|           zradius <zradius>   - sets the vertical radius to look for corpses
|           los / nolos         - toggles the check for line of sight to corpses
|           ws <weightset>      - uses this key in the ini file to get sort keys
|           mw <minimumweight>  - the minimum weight value to rez a corpse, defaults to 0
|           lobby/nolobby       - toggles special guild lobby code on or off
|
| see example ini-file for a description of features.

#include spell_routines.inc

#define CL_INIFILE click.ini

#define REZ_SUCCESS 0
#define REZ_UNABLE 1
#define REZ_TOOOLD 2
#define REZ_SKIP 3
#define REZ_ERROR 4

#define GUILDLOBBYZONEID 344

#event ConHasTimer "This corpse's resurrection time will expire in#*#"
#event ConDecay "This corpse will decay in#*#"
#event ConTooOld "This corpse is too old to be resurrected."
#event ConTooOld "This corpse is waiting to expire."
#event UnableRez "You were unable to restore the corpse to life, but you may have success with a later attempt." 

#include click_event.inc

Sub Event_UnableRez
	/varset UnableReply 1
/return

Sub Event_Hail(string Line,string Hailer,string Hailee)
	/declare cNum int local
	/if (${NoiseLevel}>3) /echo Hail: ${Hailee} by ${Hailer}
	/call FindExactPCID ${Hailer}
	/if (${Spawn[corpse ${Hailee}].ID} && ${Spawn[id ${Macro.Return}].Class.Name.Equal[cleric]}) {
		/if (${NoiseLevel}>2) /echo ${Hailee} rezzed by ${Hailer}. Added to skip list.
		/varcalc SkipListSize ${SkipListSize}+1
		/varset SkipList[${SkipListSize}] ${Hailee}
	}
/return

Sub Event_ConTooOld
	/varset GotConResponse 2
/return

Sub Event_ConHasTimer
	/varset GotConResponse 1
/return

Sub Event_ConDecay
	/varset GotCon 1
/return

Sub Main
	/call CL_InitVars

	/declare c int local 0
	:checkparams
	/if (${Defined[Param${c}]}) {
		/if (${Param${c}.Equal[radius]}) {
			/varset Radius ${Param${Math.Calc[${c}+1].Int}}
			/varcalc c ${c}+2
		} else /if (${Param${c}.Equal[zradius]}) {
			/varset ZRadius ${Param${Math.Calc[${c}+1].Int}}
			/varcalc c ${c}+2
		} else /if (${Param${c}.Equal[los]}) {
			/varset LOS 1
			/varcalc c ${c}+1
		} else /if (${Param${c}.Equal[nolos]}) {
			/varset LOS 0
			/varcalc c ${c}+1
		} else /if (${Param${c}.Equal[ws]}) {
			/varset WeightSet ${Param${Math.Calc[${c}+1].Int}}
			/varcalc c ${c}+2
		} else /if (${Param${c}.Equal[mw]}) {
			/varset MinWeight ${Param${Math.Calc[${c}+1].Int}}
			/varcalc c ${c}+2
		} else /if (${Param${c}.Equal[lobby]}) {
			/varset Lobby 1
			/varcalc c ${c}+1
		} else /if (${Param${c}.Equal[nolobby]}) {
			/varset Lobby 0
			/varcalc c ${c}+1
		}
		/if (${Defined[Param${c}]}) /goto :checkparams
	}
	/call ReadWeights ${WeightSet}
	
	/call RezCorpses
/return

Sub TimeMS(int Seconds)
	/return ${Math.Calc[${Seconds}\60].Int}m ${Math.Calc[${Seconds}%60].Int}s
/return

Sub RezCorpses
	/declare c int local
	/call BuildCorpseList
	/if (!${CorpseListSize}) {
		/if (${NoiseLevel}>0) /echo No corpses found within radius ${Radius}.
		/return
	}
	/call _Array_Sort CorpseList CorpseWeights 1 ${CorpseListSize} 1

	/declare tmpX1 int local
	/declare tmpY1 int local
	/declare tmpX2 int local
	/declare tmpY2 int local

	/varset c 0
	/if (${Zone.ID}==GUILDLOBBYZONEID && ${Lobby}) {
		/if (${NoiseLevel}>2) /echo In guild lobby. Only resurrecting players near their corpses.
	}
	/if (${NoiseLevel}>2) /echo Resurrecting with radius ${Radius}.
	:rezloop
	/varcalc c ${c}+1
	/if (${c}>${CorpseListSize}) /goto :afterrezloop
		/if (${Spawn[id ${CorpseList[${c}]} zradius ${ZRadius} radius ${Radius}].Deity.ID}) {
			/call FindExactPCID ${Spawn[id ${CorpseList[${c}]}].CleanName.Arg[1,']}
			/if (${Macro.Return}) {
				/varset tmpX1 ${Spawn[id ${Macro.Return}].X}
				/varset tmpY1 ${Spawn[id ${Macro.Return}].Y}
				/varset tmpX2 ${Spawn[id ${CorpseList[${c}]}].X}
				/varset tmpY2 ${Spawn[id ${CorpseList[${c}]}].Y}
				/if (${Zone.ID}==GUILDLOBBYZONEID && ${Lobby}) {
					/if (${Math.Distance[${tmpY1},${tmpX1}:${tmpY2},${tmpX2}]}<25 && ${Spawn[id ${Macro.Return}].Animation}==36) {
						/if (${NoiseLevel}>2) /echo ${Spawn[id ${CorpseList[${c}]}].CleanName} skipped because owner is already looting.
						/varcalc LootSkips ${LootSkips}+1
						/goto :rezloop
					} else /if (${Math.Distance[${tmpY1},${tmpX1}:${tmpY2},${tmpX2}]}>75) {
						/if (${NoiseLevel}>2) /echo ${Spawn[id ${CorpseList[${c}]}].CleanName} skipped because zone is guildlobby and owner not near corpse.
						/goto :rezloop
					}
				} else {
					/if (${Math.Distance[${tmpY1},${tmpX1}:${tmpY2},${tmpX2}]}<25 && ${Spawn[id ${Macro.Return}].Animation}==36) {
						/if (${NoiseLevel}>2) /echo ${Spawn[id ${CorpseList[${c}]}].CleanName} skipped because owner is already looting.
						/varcalc LootSkips ${LootSkips}+1
						/goto :rezloop
					}
				}
			} else /if (${Zone.ID}==GUILDLOBBYZONEID && ${Lobby}) {
				/goto :rezloop
			}
			/if (${c}>1) {
				/delay ${Math.Rand[${RandomDelay}]}
			}
			/doevents
			/call FindSkip ${Spawn[id ${CorpseList[${c}]}].CleanName.Arg[1,']}
			/if (${Macro.Return}) {
				/if (${NoiseLevel}>2) /echo ${Spawn[id ${CorpseList[${c}]}].CleanName.Arg[1,']} found in skip list. Ignoring.
				/varcalc ListSkips ${ListSkips}+1
				/goto :rezloop
			}
			/call RezID ${CorpseList[${c}]}

			/if (${Macro.Return.Equal[REZ_SUCCESS]}) {
				/if (${NoiseLevel}>3) /echo Successful: ${Spawn[id ${CorpseList[${c}]}].Name}.
				/varcalc Successful ${Successful}+1
			} else /if (${Macro.Return.Equal[REZ_UNABLE]}) {
				/if (${NoiseLevel}>3) /echo Unable to restore: ${Spawn[id ${CorpseList[${c}]}].Name}.
				/varcalc Unable ${Unable}+1
			} else /if (${Macro.Return.Equal[REZ_TOOOLD]}) {
				/if (${NoiseLevel}>3) /echo Too old: ${Spawn[id ${CorpseList[${c}]}].Name}.
				/varcalc TooOld ${TooOld}+1
			} else /if (${Macro.Return.Equal[REZ_ERROR]}) {
				/varcalc RezError ${RezError}+1
			}
		}
	/goto :rezloop
	
	:afterrezloop
		/if (${NoiseLevel}>2) /call ShowStats
	/if (${OldPrimary.NotEqual[${InvSlot[mainhand].Item.Name}]}) {
		/call EquipItem "${OldPrimary}|mainhand"
	}
/return


Sub RezID(int ID)
	/target id ${ID}
	/if (${ConCorpse}) {
		/doevents Hail
		/doevents flush
		/consider
		/varset GotCon 0
		/varset GotConResponse 0
		/varset ConTimeout 100
		
		:waitcon
			/doevents
		/if (!${GotCon} && ${ConTimeout}) /goto :waitcon
		/doevents
		/if (${GotConResponse}==2) /return REZ_TOOOLD
	}
	:rezcorpse
	/if (${UseEpic}) {
		/if (${InvSlot[mainhand].Item.Name.NotEqual[Water Sprinkler of Nem Ankh]}) {
			/call EquipItem "Water Sprinkler of Nem Ankh|mainhand"
		}
		/call AnnounceRez
		/call Cast "Water Sprinkler of Nem Ankh" item
	} else {
		:waitmana
		/if (${Me.CurrentMana}>${Math.Calc[${Spell[${RezSpell}].Mana}*1.2]}) {
			/if (!${Me.Standing}) /stand
			/call AnnounceRez
			/call Cast "${RezSpell}" gem${SpellGem} 30s
		} else {
			/if (!${Me.Sitting} || !${Me.Mount.ID}) /sit
			/delay 30
			/goto :waitmana
		}
	}
	
	/if (${Macro.Return.Equal[CAST_SUCCESS]}) {
		/varset UnableTimer 25
		/varset UnableReply 0
		:waitunable
			/doevents UnableRez
		/if (${UnableTimer} && !${UnableReply}) /goto :waitunable
		/if (!${UnableReply}) /return REZ_SUCCESS
		/return REZ_UNABLE
	} else 	/if (${Macro.Return.Equal[CAST_CANCELLED]}) {
		/return REZ_SKIP
	}	else /if (${Macro.Return.Equal[CAST_INTERRUPTED]} || ${Macro.Return.Equal[CAST_NOTREADY]}) {
		/goto :rezcorpse
	}
/return REZ_ERROR

Sub AnnounceRez
	/if (${NoiseLevel}>2) /echo Resurrecting ${Target.Name}
	/if (${Math.Rand[100]}<${AnnouncePct}) {
		/if (${AnnounceChan.NotEqual[0]}) /${AnnounceChan} ${AnnounceMsg}
		/if (${AnnounceHail}) /keypress hail
	}
	/if (${SendTell}) /tell ${Target.CleanName.Arg[1,']} ${Tell}
/return

Sub CL_InitVars

	/declare NoiseLevel int outer ${Ini[CL_INIFILE,Main,NoiseLevel,2]}

	/if (${NoiseLevel}>1) /echo Click.mac v3.00b - by blueninja
	/declare ConTimeout timer outer
	/declare CorpseList[200] int outer 0
	/declare CorpseWeights[200] int outer 0
	/declare CorpseListSize int outer 0
	/declare CurrentCorpse int outer
	/declare SkipListSize int outer 0
	/declare SkipList[50] string outer
	/declare MinWeight int outer 0
	/declare WeightSet string outer Weights
	/declare UnableTimer timer outer
	/declare UnableReply bool outer
	
	/declare Radius int outer ${Ini[CL_INIFILE,Main,Radius,200]}
	/declare ZRadius int outer ${Ini[CL_INIFILE,Main,ZRadius,100]}
	/declare LOS bool outer ${Ini[CL_INIFILE,Main,LineOfSight,1]}
	/declare Lobby bool outer ${Ini[CL_INIFILE,Main,Lobby,1]}
	/declare Tell string outer ${Ini[CL_INIFILE,Main,Tell,Inc Rez!!]}
	/declare SendTell bool outer ${Ini[CL_INIFILE,Main,SendTell,0]}

	/declare AnnounceChan string outer ${Ini[CL_INIFILE,Main,AnnounceChan,0]}
	/declare AnnouncePct int outer ${Ini[CL_INIFILE,Main,AnnouncePct,0]}
	/declare AnnounceMsg string outer ${Ini[CL_INIFILE,Main,AnnounceMsg,Rezzing %t !]}
	/declare AnnounceHail bool outer ${Ini[CL_INIFILE,Main,AnnounceHail,0]}
	
	/declare RandomDelay int outer ${Ini[CL_INIFILE,Main,RandomDelay,0]}
	
	/declare Successful int outer 0
	/declare Unable int outer 0
	/declare TooOld int outer 0
	/declare RezError int outer 0
	/declare BlackList int outer 0
	/declare ListSkips int outer 0
	/declare LootSkips int outer 0
	/declare GotCon int outer
	/declare GotConResponse int outer
	/declare ConCorpse int outer 1
	/declare OldPrimary string outer ${InvSlot[mainhand].Item.Name}
	/declare SpellGem int outer ${Ini[CL_INIFILE,Main,SpellGem,8]}
	/declare RezSpell string outer
	/declare UseEpic bool outer ${FindItem[=Water Sprinkler of Nem Ankh].ID}
	/if (!${UseEpic}) {
		/if (${Me.Book[Reviviscence]}) {
			/varset RezSpell Reviviscence
		} else /if (${Me.Book[Resurrection]}) {
			/varset RezSpell Resurrection
		} else /if (${Me.Book[Restoration]}) {
			/varset RezSpell Restoration
		} else /if (${Me.Book[Resuscitate]}) {
			/varset RezSpell Resuscitate
		} else /if (${Me.Book[Renewal]}) {
			/varset RezSpell Renewal
		} else /if (${Me.Book[Reparation]}) {
			/varset RezSpell Reparation
		} else /if (${Me.Book[Reconstitution]}) {
			/varset RezSpell Reconstitution
		} else /if (${Me.Book[Reanimation]}) {
			/varset RezSpell Reanimation
		} else {
			/if (${NoiseLevel}>0) /echo ERROR: Couldn't find resurrection spell or epic!
			/end
		}
		/if (${NoiseLevel}>2) /echo Epic not found. Using spell ${RezSpell}.
	} else {
		/if (${NoiseLevel}>2) /echo Epic found.
	}
	/declare Weights[200] string outer
	/declare WeightCount int outer 0
	
/return

Sub ReadWeights(string WSection)
	/declare c int local
	/declare sTmp string ${Ini[CL_INIFILE,${WSection}]}
	/if (${Math.Calc[${sTmp.Count[|]}-1]}) {
		/varset WeightCount ${Math.Calc[${sTmp.Count[|]}-1]}
		/for c 1 to ${WeightCount}
			/varset Weights[${c}] ${Ini[CL_INIFILE,${WSection},${sTmp.Arg[${c},|]}]}
		/next c
	}	
/return

Sub ShowStats
	/echo ---------------------------------------
	/echo Successful resurrections: ${Successful},
	/echo Unable to restore: ${Unable}, TooOld: ${TooOld}${If[${RezError}, Errors: ${RezError},]}.
	/echo Skipped due to looting: ${LootSkips}, due to hails: ${ListSkips},
	/echo due to negative weights: ${BlackList}.
	/call TimeMS ${Macro.RunTime}
	/echo Total corpses: ${CorpseListSize}. Total runtime: ${Macro.Return}
	/echo ---------------------------------------
/return

Sub FindSkip(string Name)
	/if (!${SkipListSize}) /return 0
	/declare c int local
	/for c 1 to ${SkipListSize}
		/if (${SkipList[${c}].Equal[${Name}]}) /return ${c}
	/next c
/return 0

Sub RemoveCorpse(int num)
	|Kolla om tom
	/declare c int local
	/for c ${num} to ${CorpseListSize}
		/varset CorpseList[${c}] ${CorpseList[${Math.Calc[${c}+1]}]}
	/next c
	/varset CorpseList[${CorpseListSize}] 0
	/varcalc CorpseListSize ${CorpseListSize}-1
/return

Sub BuildCorpseList
	/declare c int local
	/declare cID int local
	/declare wTmp int local
	
	/varset CorpseListSize 0
	/if (!${SpawnCount[corpse zradius ${ZRadius} radius ${Radius}]}) /return
	/for c 1 to ${SpawnCount[corpse zradius ${ZRadius} radius ${Radius}]}
		/varset cID ${NearestSpawn[${c},zradius ${ZRadius} corpse radius ${Radius}].ID}
		/if (${Spawn[id ${cID}].Deity.ID} && ((${LOS} && ${Spawn[id ${cID}].LineOfSight}) || !${LOS})) {

			/call GetCWeight ${cID}
			/if (${NoiseLevel}>3) /echo ${Spawn[id ${cID}].Name} (${Spawn[id ${cID}].Class.Name}) wt: ${Macro.Return}
			/varset wTmp ${Macro.Return}
			/if (${wTmp}<${MinWeight}) {
				/varcalc BlackList ${BlackList}+1
				/next c
			}
			/varcalc CorpseListSize ${CorpseListSize}+1
			/varset CorpseList[${CorpseListSize}] ${cID}
			/varset CorpseWeights[${CorpseListSize}] ${wTmp}
		}
	/next c
/return


Sub GetCWeight(int ID)
	/if (!${WeightCount}) /return 0
	
	/declare c int local
	/declare d int local
	/declare wTmp int local 0
	/declare wType string local
	/declare wNot bool local
	
	/for c 1 to ${WeightCount}
		/varset wType ${Weights[${c}].Arg[1,|]}
		/varset wNot ${wType.Left[1].Equal[!]}
		/if (${wNot}) /varset wType ${wType.Right[${Math.Calc[${wType.Length}-1]}]}
		/if (${wType.Equal[name]}) {
			/if (${wNot} ^^ ${Spawn[id ${ID}].CleanName.Arg[3,|].Equal[${Weights[${c}].Arg[3,|]}]}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		} else /if (${wType.Equal[guild]}) {
			/if (${Spawn[id ${ID}].Guild.Length}) {
				/if (${wNot} ^^ ${Spawn[id ${ID}].Guild.Equal[${Weights[${c}].Arg[3,|]}]}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
			} else {
				/call FindExactPCID ${Spawn[id ${ID}].CleanName.Arg[3,']}
				/if (${Macro.Return}) {
					/if (${wNot} ^^ ${Spawn[id ${Macro.Return}].Guild.Equal[${Weights[${c}].Arg[3,|]}]}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
				} else {
					/if (${wNot}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
				}
			}
		} else /if (${wType.Equal[class]}) {
			/if (${wNot} ^^ ${Spawn[id ${ID}].Class.Name.Equal[${Weights[${c}].Arg[3,|]}]}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		} else /if (${wType.Equal[ingroup]}) {
			/if (${wNot} ^^ (${Group.Members} && ${Group.Member[${Spawn[id ${ID}].CleanName.Arg[3,']}]})) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		} else /if (${wType.Equal[inraid]}) {
			/if (${wNot} ^^ ${Raid.Member[${Spawn[id ${ID}].CleanName.Arg[3,']}].Level}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		} else /if (${wType.Equal[random]}) {
			/if (${wNot} ^^ ${Weights[${c}].Arg[3,|]}<${Math.Rand[100]}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		} else /if (${wType.Equal[everyone]}) {
			/if (!${wNot}) /varcalc wTmp ${wTmp}+${Weights[${c}].Arg[2,|]}
		}
	/next c

/return ${wTmp}

Sub FindExactPCID(string Name)
	/declare CurrentID int local
	/declare FirstID int local
	/declare Counter int local 1

	/varset CurrentID ${Spawn[pc ${Name}].ID}
	
	:FESI_FindNext
		/if (!${CurrentID} || ${Spawn[id ${CurrentID}].CleanName.Equal[${Name}]}) /return ${CurrentID}
		/varset CurrentID ${Spawn[id ${Me.ID}].NearestSpawn[${Counter},pc ${Name}].ID}
		/varcalc Counter ${Counter}+1
	/goto :FESI_FindNext
	
/return 0

Sub _Array_Sort(string Array,string ArrayW,Lo,Hi,D)
    /declare L int local ${Lo}
    /declare R int local ${Hi}
    /declare P int local ${Math.Calc[(${Lo}+${Hi})\2]}
    :while1
    /if (${L}<${R}) {
        :while2
				/if (${Math.Calc[${${ArrayW}[${P}]}-${${ArrayW}[${L}]}]}>0) {
            /varcalc L ${L}+1
            /goto :while2
        }
        :while3
				/if (${Math.Calc[${${ArrayW}[${P}]}-${${ArrayW}[${R}]}]}<0) {
            /varcalc R ${R}-1
            /goto :while3
        }
        /if (${L}<=${R}) {
            /call _Array_Swap ${Array} ${ArrayW} ${L} ${R} ${D}
            /varcalc L ${L}+1
            /varcalc R ${R}-1
        }
        /goto :while1
    }
    /if (${Lo}<${R}) /call _Array_Sort ${Array} ${ArrayW} ${Lo} ${R} ${D}
    /if (${L}<${Hi}) /call _Array_Sort ${Array} ${ArrayW} ${L} ${Hi} ${D}
/return

Sub _Array_Swap(string Array,string ArrayW,int Lo,int Hi,int D)
    /declare S string local ${${Array}[${Lo}]}
    /declare W string local ${${ArrayW}[${Lo}]}
    /varset ${Array}[${Lo}] ${${Array}[${Hi}]}
    /varset ${Array}[${Hi}] ${S}
    /varset ${ArrayW}[${Lo}] ${${ArrayW}[${Hi}]}
    /varset ${ArrayW}[${Hi}] ${W}
/return