ソラマメブログ
最近のSLブックマーク

2008年02月07日

チャットキャンプのスクリプト(ログ取得追加)

前回アップしたチャットキャンプ(チャットしてるとお金が数分ごとにもらえるキャンプ)に、
ログ取得機能等を追加しました。
多分、これで実用的なチャットキャンプになったと思います。

■使い方&機能説明
・オブジェクトにスクリプトを入れて、クリックするとキャンプ開始。
・/stop campとsayするか、takeするとキャンプ停止(クリックすれば、また再開)

・/view settingとsayすると、現在の設定状況を確認。
チャットキャンプのスクリプト(ログ取得追加)

Time-Wait:何秒おきにお金を払い出すか
??%=???L$:払い出すお金の金額と確率
1time-Ave:一回に支払うお金の期待値
1min-Ave:一分間あたりに払い出すお金
1day-Ave:1日中チャットしてると払い出すお金の期待値
Soliloquy-Chat:独り言してる人にお金を払うか否か

・/view log とsayするかオブジェクトにtouchすると、動き始めてからいくら払ったかを表示。
チャットキャンプのスクリプト(ログ取得追加)


「最終発言時間 名前 払ったお金/チャットキャンプしてた合計時間」を
払った合計金額が多い人順に表示。ログが50人以上になると最終発言時刻が古い人から削除(※)。
最後の行に、払った合計金額(Total Cost)とシステムが動作時間、動作開始時刻を表示。

※50人までログがちゃんとローテーションするかためせてません。
もしヒープエラーが出たらスクリプトの「integer MAX_LOG_NUM=50;//ログをとれる数」を小さく変更してください。

/view log じゃなくて、/say logだと、みんなに聞こえる声で表示します。
チャットキャンプのスクリプト(ログ取得追加)



/clear logで上記ログをリセットします。

■注意
・必ずスクリプトの最初の、設定項目を自分に合わせて設定してください(初期値は、結構太っ腹な払い出し設定になってますw)
・お金を払う人が、お金を持っていなくてもエラーになりません(※)。お金が無くならないよう注意してくださいw
※お金を払うこと(llGiveMoney();)に成功したか否かをハンドリングする方法がないからです(もし知ってる方いたら教えてください)。

LSL (コピーはすぐ↓の「copy to clipboard」をクリックするとコピーできるよ)

//----------------------------------------------
// Totori's purse.
string VERSION=" ver2008.02.04.001";
// ======使い方==========================
// オーナーのみ以下の操作を可能
// ・配置した後、タッチするとスタート
// ・スタートした後、再度タッチするとログ表示
// /stop camp とsayするとキャンプ停止
// /show setting とsayすると現在の設定表示
// /clear log とsayするとログが消える
// /say log とsayするとログをsayする(周りに聞こえる)

//================================================
// 設定項目
//================================================

// お金を配る間隔(秒)
float WAIT=180.0;

//渡すお金と確率(合計100%にする)
list GIVE_MONEY=[
"1%=100", // 1%の確率で100L$渡す
"4%=50", // 4%の確率で50L$
"15%=30", // ・・・
"20%=20",
"20%=10",
"40%=5"

];

//独り言してる人に払う=1 / 払わない=0
integer PAY_ALONG=0;

//================================================
//設定項目終わり

list glk_speacker;// 話した人リスト
list gli_percent;
list gli_money;
integer gli_percent_num;
list glk_speacker_old;// 前回話した人リスト
integer MAX_LOG_NUM=50;//ログをとれる数



//ログ取得用
integer gi_now_time;
integer gi_total_cost;//払った合計金額
integer gi_start_time;//CAMP開始時刻
list gliiis_log; // 以下が1セットで順番に入ったリスト
// 0 integer 払出金額合計
// 1 integer 最終会話時刻(epoch)
// 2 integer 滞在時間合計(秒)
// 3 string 話した人


//毎回各関数で宣言するのが面倒くさいのでグローバルに出した
integer i;
integer len;

// GIVE_MONEYのリストを読んで
// 確率とお金をgli_percentとgli_moneyに順番に入れる
integer parseGiveMoney(){
integer total_percent; //確率合計
float expected_money;//期待値

gli_percent_num=llGetListLength(GIVE_MONEY);

llOwnerSay("ChatCamp. maked by Totori K."+VERSION);
llOwnerSay("-------------------------------------");
llOwnerSay("Time-wait="+(string)WAIT+"sec");

for(i=0;i string stmp=llList2String(GIVE_MONEY,i);
list ltmp=llParseString2List(stmp,["%="],[]);
integer a=llList2Integer(ltmp,0);
integer b=llList2Integer(ltmp,1);
total_percent+=a;
expected_money+=(float)(a*b/100.0);
gli_percent+=total_percent;
gli_money+=b;
llOwnerSay((string)a+"%="+(string)b+"L$");
}
// 平均払い出し金額を表示
llOwnerSay("1time-Ave="+(string)expected_money+"L$");
llOwnerSay("1min-Ave="+(string)(expected_money*60/WAIT)+"L$");
llOwnerSay("1hour-Ave="+(string)(expected_money*60*60/WAIT)+"L$");
llOwnerSay("1day-Ave="+(string)(expected_money*60*60*24/WAIT)+"L$");
// 独り言に対して払い出すか
if(PAY_ALONG){
llOwnerSay("Soliloquy-Chat:ok");
}else{
llOwnerSay("Soliloquy-Chat:no");
}

if(total_percent!=100){
//合計確率が100%にならない場合はエラー
llOwnerSay("ERROR:total_percent<>100%");
return 0;
}
return 1;
}

//払う金額を決める(gli_percentとgli_moneyで決める)
integer donationValue(){
integer dice=(integer)llFrand(100.0)+1;//1~100ランダム
for(i=0;i if(dice<=llList2Integer(gli_percent,i)){
return llList2Integer(gli_money,i);
}
}
return 0;
}


//発言者リストに追加(リストが更新されたら1)
integer addSpeacker(key id){
if(llGetOwnerKey(id)!=id){
return 0; //人間じゃないから無視
}
len=llGetListLength(glk_speacker);
for(i=0;i if(llList2Key(glk_speacker,i)==id){
return 0; // 記録済みの人
}
}
// お金あげる人リストに追加
glk_speacker+=id;
return 1;
}

//前回発言したことあるか?
integer checkSpeackerOld(key id){
len=llGetListLength(glk_speacker_old);
for(i=0;i if(llList2Key(glk_speacker_old,i)==id){
return 1; //話したことある
}
}
return 0;//話したこと無い
}

refleshSpeacker(){
glk_speacker_old=glk_speacker;
glk_speacker=[];
}


// idに一致するindexを出力。無い場合は最終発言時刻が古いindexを -(index+1) で返す。
integer getLogIndex(string name){
integer t;
integer old_t=gi_now_time;
integer old_i=0;

len=llGetListLength(gliiis_log);
for(i=0;i if(llList2Key(gliiis_log,i+3)==name){
return i;
}
t=llList2Integer(gliiis_log,i+1);// 最終発言時刻
if(t old_t=t;
old_i=i;
}
}
return -(old_i+1);
}

//ログ記録,
writeLog(string name,integer donation){
integer index=getLogIndex(name);
if(index>=0){
// 過去ログに記録済みの人→更新
_renewLog(index,donation);
}else{
// 過去ログに無い人→追加
gliiis_log+=donation; // 払出金額
gliiis_log+=gi_now_time; //現在時刻
gliiis_log+=0; // 滞在時間
gliiis_log+=name;

// ログの数がMAXを超えた場合は最終発言時刻が古いindexを削除)
if(llGetListLength(gliiis_log)>MAX_LOG_NUM*4){
index=-index-1;
// llOwnerSay("del old_log:"+llKey2Name(llList2Key(gliiis_log,index)));
gliiis_log=llDeleteSubList(gliiis_log,index,index+3);
}
}
}


// 滞在時刻、お金を追加更新
_renewLog(integer ii,integer mm){
integer m=llList2Integer(gliiis_log,ii+0);//お金合計
integer t=llList2Integer(gliiis_log,ii+1);//最終会話時刻
integer v=llList2Integer(gliiis_log,ii+2);//滞在時間

key k=llList2Key(gliiis_log,ii);//最終会話時刻

// 滞在時間更新
if(gi_now_time-t v+=gi_now_time-t;
}// WAIT*3以上無言だった場合は滞在時間にカウントしない)

// お金合計更新
m+=mm;

// リストに格納
gliiis_log=llListReplaceList(gliiis_log,[m,gi_now_time,v],ii,ii+2);

}

// say 1..llSayでしゃべる 0..llOwnerSayでしゃべる
viewLog(integer say){
len=llGetListLength(gliiis_log);
key id;
string mes;
gliiis_log=llListSort(gliiis_log,4,0);

for(i=0;i mes=epoch2str(llList2Integer(gliiis_log,i+1)+9*60*60)+" "; //時刻
mes+=llList2String(gliiis_log,i+3)+" "; 名前
mes+="L$"+(string)llList2Integer(gliiis_log,i); //お金
mes+="/"+(string)((integer)(llList2Integer(gliiis_log,i+2)/60))+"min"; //滞在時間
if(say){
llSay(0,mes);
}else{
llOwnerSay(mes);
}
}
integer h=(integer)((gi_now_time-gi_start_time)/60/60);
mes ="Total Cost L$";
mes+=(string)gi_total_cost;
mes+=" in "+(string)h+"hours ";
mes+=" since "+epoch2str(gi_start_time+9*60*60);

if(say){
llSay(0,mes);
}else{
llOwnerSay(mes);
}
return ;
}





// epochをYYYY-MM-DD hh:mm:ssに変換(LSL関数になさ気なので作った・・)
// JST+9にするときは、あらかじめ9*60*60足しておくこと
string epoch2str (integer epoch) {
integer work=epoch;
integer ss = work % 60;work /= 60;
integer mm = work % 60;work /= 60;
integer hh = work % 24;work /= 24;
integer day = work+1;
integer year =work/365+1970;

for (year = 1970; day >= 366; year++) {
if((!(year % 4) && ((year % 100) || !(year % 400)))){
day-=366;//閏年
}else{
day-=365;
}
}

list ltmp;
if((!(year % 4) && ((year % 100) || !(year % 400)))){
ltmp=[31,29,31,30,31,30,31,31,30,31,30,31];//閏年
}else{
ltmp=[31,28,31,30,31,30,31,31,30,31,30,31];
}

integer mon;
integer x=31;// =llList2Integer(mon,0)
for(mon=1;day>x;mon++){
day-=x;
x=llList2Integer(ltmp,mon);
}

string ret=(string)year+"/";
if(mon<10)ret+="0";
ret+=(string)mon+"/";
if(day<10)ret+="0";
ret+=(string)day+" ";
if(hh<10)ret+="0";
ret+=(string)hh+":";
if(mm<10)ret+="0";
ret+=(string)mm+":";
if(ss<10)ret+="0";
ret+=(string)ss;

return ret;
}





default{
state_entry(){
}
touch_start(integer total_number){
if(llDetectedKey(0)==llGetOwner()){
if(parseGiveMoney()){
llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
}
}
}
run_time_permissions (integer perm){
if(perm & PERMISSION_DEBIT){
llOwnerSay("chat-camp system start.");
state ready;
}else{
llOwnerSay("permission danied");
}
}
}
state ready{
state_entry(){
gi_now_time=llGetUnixTime();
refleshSpeacker();
refleshSpeacker();
gi_total_cost=0;
gliiis_log=[];
gi_start_time=gi_now_time;

llListen(0,"",NULL_KEY,"");
llSetTimerEvent(WAIT);
}
touch_start(integer total_number){
if(llDetectedKey(0)==llGetOwner()){
viewLog(0);
}
}

//動作中に(takeされた後)rezされた場合は停止
on_rez(integer i){
llOwnerSay("chat-camp system stop");
state default;
}

//誰か話したらkeyを記録
listen(integer channel, string name, key id, string mes){
gi_now_time=llGetUnixTime();

if(id==llGetOwner()){
if(mes=="/show log"||mes=="/view log"){
viewLog(0);
return;
}else if(mes=="/say log"){
viewLog(1);
return;

}else if(mes=="/clear log"){
llOwnerSay("clear log ..done");
gliiis_log=[];
gi_total_cost=0;
gi_start_time=gi_now_time;
return;
}else if(mes=="/stop camp"){
llOwnerSay("chat-camp system stop");
state default;
}else if(mes=="/show setting"||mes=="/view setting"){
parseGiveMoney();
return;
}

}
// 話した人をリストに追加。リスト更新?
if(addSpeacker(id)){
// 前に話したことある?
if(!checkSpeackerOld(id)){
string name=llKey2Name(id);
llSay(0,name+" joins chat-camp.");
}
writeLog(name,0); //ログ
}



}

timer(){
gi_now_time=llGetUnixTime();

//お金を払う時間がやってきた
len=llGetListLength(glk_speacker);
if(!PAY_ALONG && len<=1){
//話してる人が1人しかいないときは払わない
refleshSpeacker();
return;
}
//お金あげる人を決める
key lucky_key =llList2Key(glk_speacker,(integer)llFrand(len));

string lucky_name=llKey2Name(lucky_key);// 名前を調べる(名前が無いkeyはlogoff中)

if(lucky_key!=NULL_KEY && lucky_name!=""){
integer give=donationValue(); //払う金額を決める

if(give){
// あげる
llSay(0,llKey2Name(lucky_key)+" gets L$"+(string)give+".");
llGiveMoney(lucky_key,give);
gi_total_cost+=give;
writeLog(lucky_name,give); //ログ
}
}
refleshSpeacker();
}

}



2008/2/8: 短時間に数十人が発言するとメモリ足りなくなるかも・・報告きたらなおします・・


同じカテゴリー(スクリプト関連)の記事画像
チップジャーのスクリプト
同じカテゴリー(スクリプト関連)の記事
 はてブをサイドバーに表示 (2008-02-18 23:04)
 チップジャーのスクリプト (2008-02-16 17:34)
 epochを時刻に変換する関数 (2008-02-03 20:36)
 LSL色づけツール (2008-02-03 01:12)
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。