Jump to content
Sign in to follow this  
astralprojection

MvP Controller

Recommended Posts

//===== Hercules Script ======================================
// MVP Spawn Controller
//===== By: ==================================================
// astralprojektion
//===== Current Version: =====================================
// 1.3
//===== Description: =========================================
// Control MVP Spawn with script. MVP will not respawn on server start or reload using flag.
// Delete or Comment all MVP and mini boss spawn at npc/pre-re/mobs/dungeons/ or /fields.
// Make sure set at NifInvasion to make it work.
//	OnLoDDead:
//	  // Set LOD as dead ang next respawn is 5580sec
//	  $S11373 = 2; $T11373 = (gettimetick(2) + 5580);
//
//===== Additional Comments: =================================
// 1.0 Initial Release  
// 1.1 Use TimeStamp when mvp is killed
//     Fixed typo on MVP_Map array.
// 1.2 Set Variables to Global.
// 1.3 Include some Mini Boss on the controller
//     Added PvP On/Off MvP is alive
//     Integrate LOD invasion
//     Added @mvpcontroller command to reset all or a specific mvp and other settings.
//============================================================
/* Credits to Meko
https://herc.ws/board/files/file/326-array-manipulation-functions/
*/
function	script	array_find	{
	.@size = getarraysize(getarg(0));
	.@neq = getarg(2, false);
	freeloop(true);

	for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
		if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
			(!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
			freeloop(false);
			return .@i;
		}
	}

	freeloop(false);
	return -1;
}

-	script	mvpcontroller	FAKE_NPC,{
end;

OnNPCKillEvent:
	if(array_find(.mvpid, killedrid) >= 0 ){
		for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {
			if( killedrid == .mvpid[.@i] && strcharinfo(PC_MAP) == .mvpmaps$[.@i]) {
				// 1 - Alive  2 - Dead
				setd("$S"+.mvpa[.@i]+.mvpid[.@i], 2);
				// current time + respawn time (seconds)
				setd("$T"+.mvpa[.@i]+.mvpid[.@i],gettimetick(2)+(.mvptime[.@i]*60));
				setd("$P"+.mvpa[.@i]+.mvpid[.@i]+"$", strcharinfo(PC_NAME));
				if( killedrid == 1120 || killedrid == 1096 ||  killedrid == 1388 ) {
					if(.announce) announce "A mini boss monster [ "+strmobinfo(1,killedrid)+" ] at "+strcharinfo(PC_MAP)+" has been slain.",bc_all;
				} else {
					if(.announce) announce "A boss monster [ "+strmobinfo(1,killedrid)+" ] at "+strcharinfo(PC_MAP)+" has been slain.",bc_all;
					if(.pvp){
						removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
						pvpoff .mvpmaps$[.@i];
					}
				}
				break;
			}
		}
	}
	end;

OnSettings:
	while(1){
	switch(select(
		" ~ PvP On Map [ "+((.pvp)?"^28bf00Yes^000000":"^ff0000No^000000")+" ]:"+
		" ~ Announce [ "+((.announce)?"^28bf00Yes^000000":"^ff0000No^000000")+" ]:"+
		" ~ Reset All MvP:"+
		" ~ Reset Specific MvP:"+ 
		" ~ ^777777Close^000000"
	)) {
	case 1: .pvp  =! .pvp; 
		for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {
			if ( getd("$S"+.mvpa[.@i]+.mvpid[.@i]) < 2 	|| getd("$T"+.mvpa[.@i]+.mvpid[.@i]) <= gettimetick(2)  ) {
				// if mini boss, just ignore pvp
				if(.pvp){
					if(.mvpid[.@i] == 1120 || .mvpid[.@i] == 1096 || .mvpid[.@i] == 1388 ){
						//PASS THROUGH
					} else {
						setmapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
						pvpon .mvpmaps$[.@i];
					}
				} else {
					removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
					pvpoff .mvpmaps$[.@i];
				}
			}
		} 
		break;
	case 2: .announce =! .announce; break;
	case 3:
		freeloop(1);
		for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {
			setd("$S"+.mvpa[.@i]+.mvpid[.@i], 1);
			setd("$T"+.mvpa[.@i]+.mvpid[.@i], 0);
			setd("$P"+.mvpa[.@i]+.mvpid[.@i]+"$","");
			killmonsterall .mvpmaps$[.@i];
		}	
		for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {			
				if( compare( .mvpmaps$[.@i], "prt_maze03" ) && .mvpid[.@i] == 1039 ) {			// Baphomet
					monster .mvpmaps$[.@i],100,100,"--ja--",.mvpid[.@i],1;
				} else if( compare( .mvpmaps$[.@i], "treasure02" ) && .mvpid[.@i] == 1112 ) {		// Drake
					monster .mvpmaps$[.@i],101,151,"--ja--",.mvpid[.@i],1;			
				} else if( compare( .mvpmaps$[.@i], "pay_dun04" ) && .mvpid[.@i] == 1150 ) {		// moonlight
					monster .mvpmaps$[.@i],120,115,"--ja--",.mvpid[.@i],1;			
				} else if( compare( .mvpmaps$[.@i], "tur_dun04" ) && .mvpid[.@i] == 1312 ) {		// turtle
					monster .mvpmaps$[.@i],99,93,"--ja--",.mvpid[.@i],1;			
				} else if( compare( .mvpmaps$[.@i], "moc_pryd06" ) && .mvpid[.@i] == 1511 ) {		// amon
					monster .mvpmaps$[.@i],102,166,"--ja--",.mvpid[.@i],1;	
				} else if( compare( .mvpmaps$[.@i], "ayo_dun02" ) && .mvpid[.@i] == 1688 ) {		// lady
					monster .mvpmaps$[.@i],150,90,"--ja--",.mvpid[.@i],1;
				} else if( compare( .mvpmaps$[.@i], "niflheim" ) && .mvpid[.@i] == 1373 ) {		// LOD
					donpcevent("NifInvasion::OnSpawn");		
				} else {
					monster .mvpmaps$[.@i],0,0,"--ja--",.mvpid[.@i],1;	
				}

			if(.pvp){
				if(.mvpid[.@i] == 1120 || .mvpid[.@i] == 1096 || .mvpid[.@i] == 1388 ){
					//PASS THROUGH
				} else {
					setmapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
					pvpon .mvpmaps$[.@i];
				}
			} else {
				removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
				pvpoff .mvpmaps$[.@i];
			}
		}
		freeloop(0);
		dispbottom "All MVP has been reset.";
		break;
	case 4:
		set .@menu$,"";
		freeloop(1);
		for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ )
			set .@menu$, .@menu$+getmonsterinfo(.mvpid[.@i],0)+" - ("+.mvpmaps$[.@i]+"):";
		set .@menu$, .@menu$+" ~ ^777777Cancel^000000";
		freeloop(0);
		set .@i, select(.@menu$)-1;
		setd("$S"+.mvpa[.@i]+.mvpid[.@i], 1);
		setd("$T"+.mvpa[.@i]+.mvpid[.@i], 0);
		setd("$P"+.mvpa[.@i]+.mvpid[.@i]+"$","");
		killmonsterall .mvpmaps$[.@i];	
		monster .mvpmaps$[.@i],0,0,"--ja--",.mvpid[.@i],1;
		if(.pvp){
			if(.mvpid[.@i] == 1120 || .mvpid[.@i] == 1096 || .mvpid[.@i] == 1388 ){
				//PASS THROUGH
			} else {
				setmapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
				pvpon .mvpmaps$[.@i];
			}
		} else {
			removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
			pvpoff .mvpmaps$[.@i];
		}
		dispbottom "Monster [ "+strmobinfo(1,.mvpid[.@i])+" ] at "+.mvpmaps$[.@i]+" has been reset.";
		break;
	default:
		close;
	}
	}
	close;

OnTimer60000:
	// Let recheck after a minute.
	for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {
		/* $S 1 - Alive $S 2 - Dead */
		// If MvP status is not yet set
		if ( getd("$S"+.mvpa[.@i]+.mvpid[.@i]) == 2 && getd("$T"+.mvpa[.@i]+.mvpid[.@i]) <= gettimetick(2)  ) {
			// check if MvP has fixed spawn location in the map.
			if( compare( .mvpmaps$[.@i], "prt_maze03" ) && .mvpid[.@i] == 1039 ) {		// Baphomet
				monster .mvpmaps$[.@i],100,100,"--ja--",.mvpid[.@i],1;
			} else if( compare( .mvpmaps$[.@i], "treasure02" ) && .mvpid[.@i] == 1112 ) {	// Drake
				monster .mvpmaps$[.@i],101,151,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "pay_dun04" ) && .mvpid[.@i] == 1150 ) {	// moonlight
				monster .mvpmaps$[.@i],120,115,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "tur_dun04" ) && .mvpid[.@i] == 1312 ) {	// turtle
				monster .mvpmaps$[.@i],99,93,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "moc_pryd06" ) && .mvpid[.@i] == 1511 ) {	// amon
				monster .mvpmaps$[.@i],102,166,"--ja--",.mvpid[.@i],1;	
			} else if( compare( .mvpmaps$[.@i], "ayo_dun02" ) && .mvpid[.@i] == 1688 ) {	// lady
				monster .mvpmaps$[.@i],150,90,"--ja--",.mvpid[.@i],1;
			// Initiate LOD invasion at Niflheim	
			} else if( compare( .mvpmaps$[.@i], "niflheim" ) && .mvpid[.@i] == 1373 ) {	// LOD
				donpcevent("NifInvasion::OnSpawn");			
			} else {
				// Spawn the MvP at random location.
				monster .mvpmaps$[.@i],0,0,"--ja--",.mvpid[.@i],1;	
			}
			if(.announce) announce "Monster [ "+strmobinfo(1,.mvpid[.@i])+" ] at "+.mvpmaps$[.@i]+" has been spawned.",bc_all;
			// set status of MvP as ALIVE!
			setd("$S"+.mvpa[.@i]+.mvpid[.@i], 1);
			// reset killer name.
			setd("$P"+.mvpa[.@i]+.mvpid[.@i]+"$", "");
			if(.pvp){
				// if mini boss, just ignore pvp
				if(.mvpid[.@i] == 1120 || .mvpid[.@i] == 1096 || .mvpid[.@i] == 1388 ){
					//PASS THROUGH
				} else {
					setmapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
					pvpon .mvpmaps$[.@i];
				}
			} else {
				removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
				pvpoff .mvpmaps$[.@i];
			}
		}
	}
	initnpctimer();
	end;


OnCheck:
OnPCLoginEvent:
	.@rank = 0;
	query_sql    "SELECT DATABASE()", .@rag_db$;
	query_logsql "SELECT DATABASE()", .@log_db$;
	query_sql( "SELECT COUNT(`monster_id`) AS `total`,`char`.`name`,`kill_char_id` FROM "+.@log_db$+".`mvplog`"+" LEFT JOIN "+.@rag_db$+".`char` ON `char`.`char_id` = `mvplog`.`kill_char_id` WHERE `map` <> 'guild_vs5' AND DATE_FORMAT( `mvp_date`, '%Y-%m-%d') = DATE_FORMAT( now(), '%Y-%m-%d') GROUP BY `kill_char_id` ORDER BY `total` DESC LIMIT 10",.@mvptotal,.@mvpname$,.@kill_char_id );
	for( .@i = 0; .@i < getarraysize(.@kill_char_id); .@i++ ) {
		if(getcharid(CHAR_ID_CHAR) == .@kill_char_id[.@i]){
			.@rank = .@i+1; .@total = .@mvptotal[.@i];
		}
	}
	if ( .@rank > 0 && .@rank < 4 ) {
		if(countitem(.topreward) == 0){
			dispbottom "Congratulations you ranked as #"+.@rank+" MvP Hunter for today. Total kill "+.@total;
			getitembound .topreward,1,4;
			equip(.topreward);
		}
	} else {
		if(countitem(.topreward) > 0){
			delitem .topreward,countitem(.topreward);
			dispbottom "Sorry you have lost your rank as Top 3 MvP Hunter of the day.";
		}
	}
	addtimer 300000,strnpcinfo(0) + "::OnCheck";
	end;
	
OnInit:
    .topreward = 31488;  	// top mvp daily reward
	.toprange = 3; 			// Only Top 3 gets the reward
	.announce = 1; 			// shall we announce mvp kills and spawn? (yes = 1 no = 0)
	.pvp = 1;				// shall will make the map pvp?  (yes = 1 no = 0)
	bindatcmd("mvpcontroller","mvpcontroller::OnSettings",99,99);
	// Mvp ids
	setarray .mvpid[0],1511,1096,1096,1388,1039,1272,1272,1046,1046,1389,1112,1115,1115,1418,1252,1120,1120,1120,1120,1086,1492,1251,1147,1147,1059,1150,1087,1190,1038,1157,1159,1312,1373,1630,1688;
	// Mvp Index is used because there are same mvp that spawn on different maps.
	setarray .mvpa[0],1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,1,2,3,4,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1;
	// MvP maps
	setarray .mvpmaps$[0],"moc_pryd06","pay_fild04","xmas_dun01","yuno_fild02","prt_maze03","gl_chyard","gld_dun04","gef_dun02","gld_dun02","gef_dun01","treasure02","gld_dun01","pay_fild11","gon_dun03","xmas_fild01","gld_dun04","pay_fild04","prt_maze03","treasure02","prt_sewb4","ama_dun03","xmas_dun02","anthell02","gld_dun03","mjolnir_04","pay_dun04","gef_fild14","gef_fild10","moc_pryd04","in_sphinx5","moc_fild15","tur_dun04","niflheim","lou_dun03","ayo_dun02";
	// How many minutes to respawn?
	setarray .mvptime[0],60,60,60,60,120,60,480,120,480,60,120,480,120,95,120,240,60,114,32,60,91,60,120,480,120,60,60,120,60,60,120,60,93,117,420;
	freeloop(1);
	for( .@i = 0; .@i < getarraysize(.mvpid); .@i++ ) {
		// If MvP status is not yet set
		if ( getd("$S"+.mvpa[.@i]+.mvpid[.@i]) < 2 	|| getd("$T"+.mvpa[.@i]+.mvpid[.@i]) <= gettimetick(2)  ) {
			// check if MvP has fixed spawn location in the map.
			if( compare( .mvpmaps$[.@i], "prt_maze03" ) && .mvpid[.@i] == 1039 ) {		// Baphomet
				monster .mvpmaps$[.@i],100,100,"--ja--",.mvpid[.@i],1;
			} else if( compare( .mvpmaps$[.@i], "treasure02" ) && .mvpid[.@i] == 1112 ) {	// Drake
				monster .mvpmaps$[.@i],101,151,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "pay_dun04" ) && .mvpid[.@i] == 1150 ) {	// moonlight
				monster .mvpmaps$[.@i],120,115,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "tur_dun04" ) && .mvpid[.@i] == 1312 ) {	// turtle
				monster .mvpmaps$[.@i],99,93,"--ja--",.mvpid[.@i],1;			
			} else if( compare( .mvpmaps$[.@i], "moc_pryd06" ) && .mvpid[.@i] == 1511 ) {	// amon
				monster .mvpmaps$[.@i],102,166,"--ja--",.mvpid[.@i],1;	
			} else if( compare( .mvpmaps$[.@i], "ayo_dun02" ) && .mvpid[.@i] == 1688 ) {	// lady
				monster .mvpmaps$[.@i],150,90,"--ja--",.mvpid[.@i],1;
			// Initiate LOD invasion at Niflheim	
			} else if( compare( .mvpmaps$[.@i], "niflheim" ) && .mvpid[.@i] == 1373 ) {	// LOD
				donpcevent("NifInvasion::OnSpawn");			
			} else {
				// Spawn the MvP at random location.
				monster .mvpmaps$[.@i],0,0,"--ja--",.mvpid[.@i],1;	
			}
			// set status of MvP as ALIVE!
			setd("$S"+.mvpa[.@i]+.mvpid[.@i], 1);	// status is alive (1)
			// reset killer name.
			setd("$P"+.mvpa[.@i]+.mvpid[.@i]+"$", "");	// killer name reset
			if(.pvp){
				// if mini boss, just ignore pvp
				if(.mvpid[.@i] == 1120 || .mvpid[.@i] == 1096 || .mvpid[.@i] == 1388 ){
					//PASS THROUGH
				} else {
					setmapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
					pvpon .mvpmaps$[.@i];
				}
			} else {
				removemapflag .mvpmaps$[.@i], mf_pvp_nocalcrank;
				pvpoff .mvpmaps$[.@i];
			}
		}
	}
	freeloop(0);
	initnpctimer();
	end;
}

/* If you want your player have access to spawn time, you can use this function to display status of each MvP and who killed them
{
	Id: 501
	AegisName: "Red_Potion"
	Name: "Red Potion"
	Type: "IT_HEALING"
	Buy: 50
	Weight: 70
	Script: <" callfunc "F_MVPTime"; ">
},
*/

function	script	F_MVPTime	{
	mes "^FF0000MvP Status^000000";
	for( .@i = 0; .@i < getarraysize(getvariableofnpc(.mvpid,"mvpcontroller")); .@i++ ) {
		.@time =  getd("$T" +getvariableofnpc(.mvpindex[.@i],"mvpcontroller") + getvariableofnpc(.mvpid[.@i],"mvpcontroller"));
		.@alive = getd("$S" +getvariableofnpc(.mvpindex[.@i],"mvpcontroller") + getvariableofnpc(.mvpid[.@i],"mvpcontroller"));

		set .@hours, (.@time - gettimetick(2)) / 3600;
		set .@mins,  (.@time - gettimetick(2))%3600/60;
		set .@secs,  (.@time - gettimetick(2))%60;

		set .@mobname$,getmonsterinfo( getvariableofnpc(.mvpid[.@i], "mvpcontroller"),0 );
		set .@map$,getvariableofnpc(.mvpmaps$[.@i], "mvpcontroller");
		set .@player$,getd("$P"+getvariableofnpc(.mvpindex[.@i], "mvpcontroller") + getvariableofnpc(.mvpid[.@i], "mvpcontroller") +"$");
		
		mes ((.@alive == 1) ? "[ ^01DF01+^000000 ]" : "[ ^FF0000x^000000 ]")+((getstrlen( .@mobname$ ) > 10 ) ? " ^0055FF"+substr(.@mobname$,0, 10)+"^000000" : " ^0055FF"+.@mobname$+"^000000")+" ^777777"+.@map$+"^000000 ";
		if( .@alive == 2 ) {
			mes "^FF0000"+((.@hours) ? .@hours +"h" : "")+" "+((.@mins)  ? .@mins  +"m" : "")+" "+((.@secs)  ? .@secs  +"s" : "")+"^000000 "+"^777777 kiiled by "+.@player$+"^000000";
		}
	}
	close;
}

What does it do?
-  prevents spawn of mvp on each server starts or reload.
-  spawns mvp or mini only at specific time based when it was killed + spawn time
-  reward x top mvp killers.

Cons:
- you can not use convex mirrors to show mvp in the map
- you can not find mvp using @whereis.

How to use:
- Delete or Comment target MVP and mini boss spawn from your npc/pre-re/mobs/dungeons/ or /fields.
- Add these mvps to array.

FAQ:
#Q1 What the heck is this?

	setarray .mvpa[0],1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,1,2,3,4,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1;

#A1: since there are same kind of MVP spawn on multile map (i.e Angeling spawns at pay_fild04, xmas_dun01, yuno_fild03) those numbers are the unique identifiers. 
if there is only 1 spawn, then just write 1. 
succeeding spawn is 2  then 3 ....

All other suggestions to simplify and improve @AnnieRuru yohoo! my master.  
 

Edited by astralprojection

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.