Writing to file?

Pazleysox

Member
Please explain how this could happen. Provide your code that produces this outcome, because I'd have to put in some intentional effort to replicate your result. Maybe I just don't know what you mean.

It doesn't happen. I was wondering if there was a way to MAKE it happen...
 

Bale

Minion
Yes. Sure. Build the string yourself.

Code:
string player_list;
foreach player in clannies {
   if(length(player_list) > 0)
      player_list += ", ";
   player_list += player
}


Then do whatever you wish with that string. My advice should stop there because I don't know where you're going with this. But for example, if you want to use player_list as the information to save to a file, then you need a key (the date?) to use as the first field. Like...

Code:
string [string] save_data;
file_to_map("whosinclan.txt", save_data );

string player_list;
foreach player in who_clan() {
   if(length(player_list) > 0)
      player_list += ", ";
   player_list += player
}

save_data[ now_to_string("yyMMddHHmmss" ) ] = player_list;
map_to_file( save_data, "whosinclan.txt");
 

xKiv

Active member
PHP:
{
boolean [string] clannies = who_clan();
foreach clannie in clannies {

map_to_file( clannies , "whosinclan.txt" );
}

Do I read that wrong, or does it really write (and rewrite) the enire file N times (where N is number of clannies)?
 

Bale

Minion
Technically you could, but I really don't think it would be advantageous, especially since important tab characters will be removed. Unless you didn't care about the person receiving the kmail being able to reliably reconstitute the map, in which case.. Yay, go for it!

As with most of your questions I just don't have the context to be sure my answer is right for your needs. Perhaps you could try telling us the problem so that we can find a good solution rather than ask if your solution will answer an unknown problem.
 

Pazleysox

Member
I'm working on a chatbot for my clan. Someone brought up today that they would love to have a list of players that have helped in Dreadsylvania in the past, and what class they currently are now. (Knowing their level too would be really nice)

I've figured out how to code players names, and class, into a map. I don't think figuring out what level someone is with all the custom titles though.

I want the bot to do a search, and send the requester a printout when requested.
 

Pazleysox

Member
Checking said player's clan is much easier than checking profile.

searchplayer.php also works.

PHP:
string page = visit_url("searchplayer.php?searching=Yep.&searchstring="+playerName+"&searchlevel=&searchranking=&hardcoreonly=0");
string page = visit_url("searchplayer.php?searching=Yep.&searchstring="+url_encode(player)+"&searchlevel=&searchranking=&hardcoreonly=0")
}

I found these 2 snippets of code in the forums. Neither of them work, because the searchplayer.php opens in a new tab, which mafia doesn't like, and if I force it in a mini browser, I get logged off...

I can't figure out how to check a players clan.

PHP:
> ashref clan

void chat_clan( string )
void chat_clan( string, string )
int get_clan_id( )
int [item] get_clan_lounge( )
string get_clan_name( )
int [string] get_clan_rumpus( )
boolean [string] who_clan( )
Code:
string get_clan_name()

Returns the clan name for the logged-in character.
played around with this for a bit today... Couldn't figure it out.
 
Last edited:

Pazleysox

Member
Ok, I've figured out how to get the info I want into a map, I've figured out how to recall that info, and I've figured out how to send it via k-mail.

I'm trying now to figure out how to get all the data onto one line, separated with "," like the code above that Bale gave me.

I'm also still trying to figure out how to get players level.
PHP:
int [item] map;
map[$item[adder]] = 0;
boolean [string] myclass;
string [int] ordinal;
string [int] my_list;
string paz = visit_url( "showplayer.php?who=352918".to_string() );
{

	if(paz.contains_text ( $class[sauceror])) 
	{	ordinal [0] = "paz is a sauceror";	}
	if(paz.contains_text ( $class[pastamancer]))
	{	ordinal [0] = "paz is a pastamancer";	}
	if(paz.contains_text ( $class[disco bandit]))
	{	ordinal [0] = "paz is a disco bandit";	}
	if(paz.contains_text ( $class[accordion thief]))
	{	ordinal [0] = "paz is a accordion thief";	}
	if(paz.contains_text ( $class[turtle tamer]))
	{	ordinal [0] = "paz is a turtle tamer";	}
	if(paz.contains_text ( $class[seal clubber]))
	{	ordinal [0] = "paz is a seal clubber";	}

	string cowmanbob = visit_url( "showplayer.php?who=840337".to_string() );
{
	if(cowmanbob.contains_text ( $class[sauceror])) 
	{	ordinal [1] = "cowmanbob is a sauceror";	}
map_to_file ( ordinal, "searchplayerbot.txt");
print("File mapped");

file_to_map( "searchplayerbot.txt" , my_list);
for i from 0 to (count(my_list) - 1) {
   print( my_list[i] );
	kmail("pazsox", my_list[i], 0, map);

Now I'm sure those who understand coding better than I do can make this easier, but I figured it out on my own, and I'm quite happy with that.

Here's my output:
Code:
searchplayerbot.txt
0	paz is a seal clubber
1	cowmanbob is a sauceror

k-mail:New! From PazSox (#352918) [reply] [quoted]
Date: Wednesday, April 05, 2017, 10:52AM

    cowmanbob is a sauceror

	New! From PazSox (#352918) [reply] [quoted]
Date: Wednesday, April 05, 2017, 10:52AM

    paz is a seal clubber

I would like to see:
cowmanbob is a sauceror, pazsox is a seal clubber, etc...
 
Last edited:

Bale

Minion
Two things. First... OMG, please don't turn a string into a string. It just makes me feel woozy.

Secondly, you might want to use a function called get_player_id() which will turn "cowmanbob" into "840337".
 
FYI, if you're going to be parsing pages for information, it would probably behoove you to pick up some regex, which is supported by mafia. I whipped up the below script which, if you save this as "showplayer.ash" in your mafia relay\ folder, will parse out the player's name, id, level, and class, and spit that info back to the CLI as well as store it in properties. You can modify this to suit your needs, or if you want to just use this as your showplayer.ash, you could then call your visit_url by itself without bothering to parse it yourself and pull the info you need from the appropriate properties.

Code:
// showplayer.ash

buffer process_profile(buffer page) {
	matcher m = create_matcher( "<center><b>([^<]+)</b> \\(\\#(\\d+)\\)<br>[^\\d]*(\\d+)[^\\d]*<br>", page );
	if( m.find() ) {
		print("Name: " + m.group(1));
		print("ID: " + m.group(2));
		print("Level: " + m.group(3));
		set_property( "lastViewedName", m.group(1) );
		set_property( "lastViewedID", m.group(2) );
		set_property( "lastViewedLevel", m.group(3) );
	}
	m = create_matcher( "<b>Class:</b></td><td>([^<]+)</td>", page );
	if( m.find() ) {
		print("Class: " + m.group(1));
		set_property( "lastViewedClass", m.group(1) );
	}
	return page;
}

void main() {
	visit_url().process_profile().write();
}

Even if you don't really understand those regexes yet, you can probably see how understanding them and pulling the info out of the page as it's displayed is a better option than running a bunch of contains_text's looking for specific classes - unless the actual code of the page changes, these regexes will work for all current and future class paths as well.

As far as putting all your info on one line, that's pretty straightforward:

Code:
file_to_map( "searchplayerbot.txt" , my_list);
string temp = "";
for i from 0 to (count(my_list) - 1) {
   print( my_list[i] );
   if( i > 0 ) temp += ", ";
   temp += my_list[i];
}
kmail("pazsox", my_list[i], 0, map);


Edit: After checking a few profiles this doesn't always work due to the sheer number of effects and things on a user's profile page. A better option might be a feature request for an ash function to do a /whois and return a string containing the response, maybe something like slash_whois(string player) or get_player_info(string player).
 
Last edited:

heeheehee

Developer
Staff member
showplayer.php works just fine for me, using the link you specified:

Code:
record PlayerStat {
  int lvl;
  class cls;
};

PlayerStat get_player(string playerName) {
  string playerId = get_player_id(playerName);
  string page = visit_url("searchplayer.php?searching=Yep.&searchstring="+playerName+"&searchlevel=&searchranking=&hardcoreonly=0");

  // We don't care about the player's capitalization, and this is possibly more efficient than converting the page to lowercase.
  // Group 1 is the player level; group 2 is the player class.
  matcher m = create_matcher('showplayer\\.php\\?who=' + playerId + '">[^<]+</a></b> (?:<br>\\(<a target=mainpane href="showclan\\.php\\?whichclan=\\d+">[^>]+</a>\\))?</td><td valign=top class=small>' + playerId + '</td><td valign=top class=small>(\\d+)</td><td class=small valign=top>([^<]+)</td></tr>', page);
  if (m.find()) {
    return new PlayerStat(m.group(1).to_int(), m.group(2).to_class());
  }
  // No player found.
  return new PlayerStat(0, $class[none]);
}
 

Pazleysox

Member
As far as putting all your info on one line, that's pretty straightforward:

Code:
file_to_map( "searchplayerbot.txt" , my_list);
string temp = "";
for i from 0 to (count(my_list) - 1) {
   print( my_list[i] );
   if( i > 0 ) temp += ", ";
   temp += my_list[i];
}
kmail("pazsox", my_list[i], 0, map);

This code didn't work for me. I'll play around with it today
 
Last edited:

Pazleysox

Member
showplayer.php works just fine for me, using the link you specified:

Code:
record PlayerStat {
  int lvl;
  class cls;
};

PlayerStat get_player(string playerName) {
  string playerId = get_player_id(playerName);
  string page = visit_url("searchplayer.php?searching=Yep.&searchstring="+playerName+"&searchlevel=&searchranking=&hardcoreonly=0");

  // We don't care about the player's capitalization, and this is possibly more efficient than converting the page to lowercase.
  // Group 1 is the player level; group 2 is the player class.
  matcher m = create_matcher('showplayer\\.php\\?who=' + playerId + '">[^<]+</a></b> (?:<br>\\(<a target=mainpane href="showclan\\.php\\?whichclan=\\d+">[^>]+</a>\\))?</td><td valign=top class=small>' + playerId + '</td><td valign=top class=small>(\\d+)</td><td class=small valign=top>([^<]+)</td></tr>', page);
  if (m.find()) {
    return new PlayerStat(m.group(1).to_int(), m.group(2).to_class());
  }
  // No player found.
  return new PlayerStat(0, $class[none]);
}
umm... I tried to make this my searchplayer.ash file, and it didn't seem to care for it... I tried mixing it with smelltastic's script, but I'm not savvy enough to figure it out...
 

Pazleysox

Member
looking back at it it's clear the my_list in the last kmail line should've been changed to temp


Works like a dream, but it's sending multiple k-mails. 1 per line of the map. Progressively adding more players with a ",". (I currently have 3 names)

k-mail 1:
name 1
k-mail 2:
name 1, name 2
k-mail 3
name 1, name 2, name 3

I really only need k-mail X, where X is the number of names in the map.
 

Pazleysox

Member
Sounds like you have the kmail inside the loop.

having
Code:
kmail("pazsox", my_list[i], 0, map);
outside the loop didn't work, so I put it inside. Switching the my_list to temp, and then putting it outside (as you suggested) it worked like a dream.
 
so, extracting player info from a search seems like a generally useful thing so I made this, not sure if you're already satisfied with what you've got but here it is anyway. I wasn't even thinking about using searchplayer.php before which is much better than using the profile page. heeheehee already did the level etc but I just wanted to make it more generalized.

Code:
// getplayers.ash (not a relay script, import it into your own script and call GetPlayer or GetPlayers)

record playerdata {
	string name;
	string id;
	string cclass;
	int level;
	string clanname;
	string clanid;
};

playerdata[int] GetPlayers(string search) {
	playerdata[int] ret;
	
	buffer page = visit_url( "searchplayer.php?searching=Yep.&searchstring=" + search.url_encode() );
	
	matcher m = create_matcher( "href=\"showplayer.php\\?who=(\\d+)\">([^<]+)</a></b> (<br>\\(<a target=mainpane href=\"showclan.php\\?whichclan=(\\d+)\">([^<]+)" +
						"</a>\\))?</td><td valign=top class=small>(\\d+)</td><td valign=top class=small>(\\d+)</td><td class=small valign=top>([^<]+)</td>", page );
	
	// Groups:
	// 1: Player ID, 2: Player Name, 3: Clan HTML, 4: Clan ID, 5: Clan Name, 6: Player ID again, 7: Player Level, 8: Player Class
	
	while( m.find() ) {
		int i = ret.count();
		ret[i].name = m.group(2);
		ret[i].id = m.group(1);
		ret[i].cclass = m.group(8);
		ret[i].level = m.group(7).to_int();
		ret[i].clanname = m.group(5);
		ret[i].clanid = m.group(4);
	}
	
	return ret;
}

// The only way to get a specific player is to search on their name and check the responses for a match.
playerdata GetPlayer(string pname) {
	playerdata[int] players = GetPlayers(pname);
	foreach i,p in players {
		if( p.name.to_lower_case() == pname.to_lower_case() )
			return p;
	}
	print("Player \"" + pname + "\" not found!", "red");
	return new playerdata;
}

void PrintPlayers(string search) {
	playerdata[int] players = GetPlayers(search);
	
	foreach i,p in players {
		print( "Player found: " + p.name + " the level " + p.level.to_string() + " " + p.cclass + (p.clanname!=""?", in clan " + p.clanname:"") + "!" );
	}
}

Then to use it you'd do something like

Code:
import "getplayers.ash"; // At top of script

// rest of your script goes here

file_to_map( "searchplayerbot.txt" , my_list);
playerdata player;
string temp = "";
foreach i,playername in my_list {
	player = GetPlayer( playername );
	if( player.name != "" ) {
		if( temp != "" ) temp += ", ";
		temp += player.name + " the level " + player.level + " " + player.cclass;
	} else {
		print( "Error: Player " + playername + " not found in search!", "red" );
	}
}
kmail("pazsox", temp, 0, map);
 
Last edited:
Top