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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...

Important Information

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