From cb44aff61ed172eb338535078d772090b124d465 Mon Sep 17 00:00:00 2001 From: veider Date: Mon, 28 Mar 2005 21:25:11 +0000 Subject: git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/stable@1316 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char_sql/char.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---- src/char_sql/char.h | 4 +++ src/char_sql/int_party.c | 36 ++++++++++++++++++------- src/common/mmo.h | 3 +++ src/map/atcommand.c | 62 ++++++++++++++++++++++++++++++++++++++++++ src/map/atcommand.h | 1 + src/map/charcommand.c | 42 +++++++++++++++++++++++++++++ src/map/charcommand.h | 2 ++ src/map/clif.c | 2 +- src/map/map.h | 3 +++ src/map/pc.c | 43 ++++++++++++++++++++++++++--- src/map/pc.h | 1 + src/map/pet.c | 5 ++-- src/map/script.c | 2 +- src/map/skill.c | 4 +-- 15 files changed, 254 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/char_sql/char.c b/src/char_sql/char.c index 6b122974f..0d3fc3d35 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -415,7 +415,8 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){ (p->clothes_color != cp->clothes_color) || (p->weapon != cp->weapon) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || - (p->partner_id != cp->partner_id)) { + (p->partner_id != cp->partner_id) || (p->father != cp->father) || + (p->mother != cp->mother) || (p->child != cp->child)) { //}//---------------------------test count------------------------------ //check party_exist @@ -457,7 +458,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){ "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," "`option`='%d',`karma`='%d',`manner`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d'," "`hair`='%d',`hair_color`='%d',`clothes_color`='%d',`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d',`partner_id`='%d' WHERE `account_id`='%d' AND `char_id` = '%d'", + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d',`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d' WHERE `account_id`='%d' AND `char_id` = '%d'", char_db, p->class_, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, @@ -466,7 +467,8 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){ p->hair, p->hair_color, p->clothes_color, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->last_point.map, p->last_point.x, p->last_point.y, - p->save_point.map, p->save_point.x, p->save_point.y, p->partner_id, p->account_id, p->char_id + p->save_point.map, p->save_point.x, p->save_point.y, p->partner_id, p->father, p->mother, + p->child, p->account_id, p->char_id ); if(mysql_query(&mysql_handle, tmp_sql)) { @@ -799,7 +801,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus *p, int online){ sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`hair`,`hair_color`," "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`," - "`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR + "`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id`, `father`, `mother`, `child` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR if (mysql_query(&mysql_handle, tmp_sql)) { printf("DB server Error (select `char2`)- %s\n", mysql_error(&mysql_handle)); } @@ -817,7 +819,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus *p, int online){ p->head_top = atoi(sql_row[11]); p->head_mid = atoi(sql_row[12]); p->head_bottom = atoi(sql_row[13]); strcpy(p->last_point.map,sql_row[14]); p->last_point.x = atoi(sql_row[15]); p->last_point.y = atoi(sql_row[16]); strcpy(p->save_point.map,sql_row[17]); p->save_point.x = atoi(sql_row[18]); p->save_point.y = atoi(sql_row[19]); - p->partner_id = atoi(sql_row[20]); + p->partner_id = atoi(sql_row[20]); p->father = atoi(sql_row[21]); p->mother = atoi(sql_row[22]); p->child = atoi(sql_row[23]); //free mysql result. mysql_free_result(sql_res); @@ -3564,3 +3566,61 @@ int debug_mysql_query(char *file, int line, void *mysql, const char *q) { #endif return mysql_query((MYSQL *) mysql, q); } + +int char_child(int parent_id, int child_id) { + int tmp_id = 0; + sprintf (tmp_sql, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id); + if (mysql_query (&mysql_handle, tmp_sql)) { + printf ("DB server Error (select `char2`)- %s\n", mysql_error (&mysql_handle)); + } + sql_res = mysql_store_result (&mysql_handle); + if (sql_res) { + sql_row = mysql_fetch_row (sql_res); + tmp_id = atoi (sql_row[0]); + mysql_free_result (sql_res); + } + else + printf("CHAR: child Failed!\n"); + if ( tmp_id == child_id ) + return 1; + else + return 0; +} + +int char_married(int pl1,int pl2) { + int tmp_id = 0; + sprintf (tmp_sql, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1); + if (mysql_query (&mysql_handle, tmp_sql)) { + printf ("DB server Error (select `char2`)- %s\n", mysql_error (&mysql_handle)); + } + sql_res = mysql_store_result (&mysql_handle); + if (sql_res) { + sql_row = mysql_fetch_row (sql_res); + tmp_id = atoi (sql_row[0]); + mysql_free_result (sql_res); + } + else + printf("CHAR: married Failed!\n"); + if ( tmp_id == pl2 ) + return 1; + else + return 0; +} + +int char_nick2id (char *name) { + int char_id = 0; + sprintf (tmp_sql, "SELECT `char_id` FROM `%s` WHERE `name` = '%s'", char_db, name); + if (mysql_query (&mysql_handle, tmp_sql)) { + printf ("DB server Error (select `char2`)- %s\n", mysql_error (&mysql_handle)); + } + sql_res = mysql_store_result (&mysql_handle); + if (sql_res) { + sql_row = mysql_fetch_row (sql_res); + char_id = atoi (sql_row[0]); + mysql_free_result (sql_res); + } + else + printf ("CHAR: nick2id Failed!\n"); + return char_id; +} + diff --git a/src/char_sql/char.h b/src/char_sql/char.h index 81ce65b8e..74bb28cf1 100644 --- a/src/char_sql/char.h +++ b/src/char_sql/char.h @@ -45,6 +45,10 @@ int mapif_sendall(unsigned char *buf,unsigned int len); int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len); int mapif_send(int fd,unsigned char *buf,unsigned int len); +int char_nick2id (char *name); +int char_married(int pl1,int pl2); +int char_child(int parent_id, int child_id); + extern int autosave_interval; extern char db_path[]; extern char char_db[256]; diff --git a/src/char_sql/int_party.c b/src/char_sql/int_party.c index 03392feb6..430385110 100644 --- a/src/char_sql/int_party.c +++ b/src/char_sql/int_party.c @@ -293,16 +293,32 @@ struct party* search_partyname(char *str) // EXP公平分配できるかチェック int party_check_exp_share(struct party *p) { - int i; - int maxlv=0,minlv=0x7fffffff; - for(i=0;imember[i].lv; - if( p->member[i].online ){ - if( lv < minlv ) minlv=lv; - if( maxlv < lv ) maxlv=lv; - } - } - return (maxlv==0 || maxlv-minlv<=party_share_level); + int i, dudes=0; + int pl1=0,pl2=0,pl3=0; + int maxlv=0,minlv=0x7fffffff; + for(i=0;imember[i].lv; + if (!lv) continue; + if( p->member[i].online ){ + if( lv < minlv ) minlv=lv; + if( maxlv < lv ) maxlv=lv; + if( lv >= 70 ) dudes+=1000; + dudes++; + } + } + if((dudes/1000 >= 2) && (dudes%1000 == 3) && (!strcmp(p->member[0].map,p->member[1].map)) && (!strcmp(p->member[1].map,p->member[2].map))) { + pl1=char_nick2id(p->member[0].name); + pl2=char_nick2id(p->member[1].name); + pl3=char_nick2id(p->member[2].name); + printf("PARTY: group of 3 Id1 %d lv %d name %s Id2 %d lv %d name %s Id3 %d lv %d name %s\n",pl1,p->member[0].lv,p->member[0].name,pl2,p->member[1].lv,p->member[1].name,pl3,p->member[2].lv,p->member[2].name); + if (char_married(pl1,pl2) && char_child(pl1,pl3)) + return 1; + if (char_married(pl1,pl3) && char_child(pl1,pl2)) + return 1; + if (char_married(pl2,pl3) && char_child(pl2,pl1)) + return 1; + } + return (maxlv==0 || maxlv-minlv<=party_share_level); } // Is there any member in the party? int party_check_empty(struct party *p) diff --git a/src/common/mmo.h b/src/common/mmo.h index 9cb9477d8..b61af6658 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -129,6 +129,9 @@ struct mmo_charstatus { int char_id; int account_id; int partner_id; + int father; + int mother; + int child; int base_exp,job_exp,zeny; diff --git a/src/map/atcommand.c b/src/map/atcommand.c index bc11123b9..55a08873c 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -260,6 +260,7 @@ ACMD_FUNC(undisguiseall); ACMD_FUNC(disguiseall); ACMD_FUNC(changelook); ACMD_FUNC(mobinfo); //by Lupus +ACMD_FUNC(adopt); // by Veider /*========================================== *AtCommandInfo atcommand_info[]構造体の定義 @@ -541,6 +542,8 @@ static AtCommandInfo atcommand_info[] = { { AtCommand_MobInfo, "@mobinfo", 1, atcommand_mobinfo }, // [Lupus] { AtCommand_MobInfo, "@monsterinfo", 1, atcommand_mobinfo }, // [Lupus] { AtCommand_MobInfo, "@mi", 1, atcommand_mobinfo }, // [Lupus] + { AtCommand_Adopt, "@adopt", 40, atcommand_adopt }, // [Veider] + // add new commands before this line { AtCommand_Unknown, NULL, 1, NULL } }; @@ -9069,3 +9072,62 @@ int atcommand_mobinfo( return 0; } + +/*========================================== + * @adopt by [Veider] + * + * adopt a novice + *------------------------------------------ + */ +int +atcommand_adopt(const int fd, struct map_session_data* sd, +const char* command, const char* message) +{ + struct map_session_data *pl_sd1 = NULL; + struct map_session_data *pl_sd2 = NULL; + struct map_session_data *pl_sd3 = NULL; + char player1[255], player2[255], player3[255]; + + nullpo_retr(-1, sd); + + if (!message || !*message) + return -1; + + if (sscanf(message, "%[^,],%[^,],%[^\r\n]", player1, player2, player3) != 3) { + clif_displaymessage(fd, "usage: @adopt ."); + return -1; + } + + printf("Adopting: --%s--%s--%s--\n",player1,player2,player3); + + if((pl_sd1=map_nick2sd((char *) player1)) == NULL) { + sprintf(player2, "Cannot find player %s online", player1); + clif_displaymessage(fd, player2); + return -1; + } + + if((pl_sd2=map_nick2sd((char *) player2)) == NULL) { + sprintf(player1, "Cannot find player %s online", player2); + clif_displaymessage(fd, player1); + return -1; + } + + if((pl_sd3=map_nick2sd((char *) player3)) == NULL) { + sprintf(player1, "Cannot find player %s online", player3); + clif_displaymessage(fd, player1); + return -1; + } + + if((pl_sd1->status.base_level < 70) || (pl_sd2->status.base_level < 70)){ + clif_displaymessage(fd, "They are too young to be parents!"); + return -1; + } + + if (pc_adoption(pl_sd1, pl_sd2, pl_sd3) == 0) { + clif_displaymessage(fd, "They are family.. wish them luck"); + return 0; + } + else + return -1; +} + diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 14a912ab1..f74ebeef3 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -241,6 +241,7 @@ enum AtCommandType { AtCommand_ChangeLook, AtCommand_AutoLoot, //by Upa-Kun AtCommand_MobInfo, //by Lupus + AtCommand_Adopt, // by Veider // end AtCommand_Unknown, diff --git a/src/map/charcommand.c b/src/map/charcommand.c index 40961f39e..ab57a6b39 100644 --- a/src/map/charcommand.c +++ b/src/map/charcommand.c @@ -51,6 +51,8 @@ CCMD_FUNC(storagelist); CCMD_FUNC(item); CCMD_FUNC(warp); CCMD_FUNC(zeny); +CCMD_FUNC(showexp); +CCMD_FUNC(showdelay); #ifdef TXT_ONLY /* TXT_ONLY */ @@ -88,6 +90,9 @@ static CharCommandInfo charcommand_info[] = { { CharCommandWarp, "#rura", 60, charcommand_warp }, { CharCommandWarp, "#rura+", 60, charcommand_warp }, { CharCommandZeny, "#zeny", 60, charcommand_zeny }, + { CharCommandShowExp, "#showexp", 0, charcommand_showexp}, + { CharCommandShowDelay, "#showdelay", 0, charcommand_showdelay}, + #ifdef TXT_ONLY /* TXT_ONLY */ @@ -1213,3 +1218,40 @@ int charcommand_zeny( return 0; } + +/*=================================== + * Remove some messages + *----------------------------------- + */ +int charcommand_showexp( + const int fd, struct map_session_data* sd, + const char* command, const char* message) +{ + if (sd->noexp) { + sd->noexp = 0; + clif_displaymessage(fd, "Gained exp is now shown"); + return 0; + } + else { + sd->noexp = 1; + clif_displaymessage(fd, "Gained exp is now NOT shown"); + return 0; + } +} + +int charcommand_showdelay( + const int fd, struct map_session_data* sd, + const char* command, const char* message) +{ + if (sd->nodelay) { + sd->nodelay = 0; + clif_displaymessage(fd, "Skill delay failure is now shown"); + return 0; + } + else { + sd->nodelay = 1; + clif_displaymessage(fd, "Skill delay failure is NOT now shown"); + return 0; + } +} + diff --git a/src/map/charcommand.h b/src/map/charcommand.h index 0bc3b3f8a..7c1618cca 100644 --- a/src/map/charcommand.h +++ b/src/map/charcommand.h @@ -18,6 +18,8 @@ enum CharCommandType { CharCommandItem, // by MC Cameri CharCommandWarp, CharCommandZeny, + CharCommandShowDelay, + CharCommandShowExp, #ifdef TXT_ONLY /* TXT_ONLY */ diff --git a/src/map/clif.c b/src/map/clif.c index a3dea154f..5d34e0f64 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4333,7 +4333,7 @@ int clif_skill_fail(struct map_session_data *sd,int skill_id,int type,int btype) sd->skillid = sd->skilllv = -1; sd->skillitem = sd->skillitemlv = -1; - if(type==0x4 && battle_config.display_delay_skill_fail==0){ + if(type==0x4 && (battle_config.display_delay_skill_fail==0 || sd->nodelay)){ return 0; } diff --git a/src/map/map.h b/src/map/map.h index 2af4b9b4d..b25e6f05a 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -360,6 +360,9 @@ struct map_session_data { unsigned char change_level; // [celest] int autoloot; //by Upa-Kun + unsigned nodelay :1; + unsigned noexp :1; + unsigned detach :1; #ifndef TXT_ONLY int mail_counter; // mail counter for mail system [Valaris] diff --git a/src/map/pc.c b/src/map/pc.c index 7fb2bb42b..c9b8755de 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -47,6 +47,8 @@ static int exp_table[14][MAX_LEVEL]; static short statp[MAX_LEVEL]; +extern char msg_table[1000][256]; + // h-files are for declarations, not for implementations... [Shinomori] struct skill_tree_entry skill_tree[3][25][MAX_SKILL_TREE]; // timer for night.day implementation @@ -1153,6 +1155,7 @@ int pc_checkweighticon(struct map_session_data *sd) */ int pc_bonus(struct map_session_data *sd,int type,int val) { + int i; nullpo_retr(0, sd); switch(type){ @@ -1588,7 +1591,6 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_DAMAGE_WHEN_UNEQUIP: if(!sd->state.lr_flag) { - int i; for (i=0; i<11; i++) { if (sd->inventory_data[current_equip_item_index]->equip & equip_pos[i]) { sd->unequip_losehp[i] += val; @@ -1599,7 +1601,6 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_LOSESP_WHEN_UNEQUIP: if(!sd->state.lr_flag) { - int i; for (i=0; i<11; i++) { if (sd->inventory_data[current_equip_item_index]->equip & equip_pos[i]) { sd->unequip_losesp[i] += val; @@ -3968,6 +3969,8 @@ int pc_checkjoblevelup(struct map_session_data *sd) int pc_gainexp(struct map_session_data *sd,int base_exp,int job_exp) { char output[256]; + float nextbp=0, nextjp=0; + int nextb=0, nextj=0; nullpo_retr(0, sd); if(sd->bl.prev == NULL || pc_isdead(sd)) @@ -3992,6 +3995,12 @@ int pc_gainexp(struct map_session_data *sd,int base_exp,int job_exp) if (base_exp < 0) base_exp = 0; } + nextb = pc_nextbaseexp(sd); + nextj = pc_nextjobexp(sd); + if (nextb > 0) + nextbp = (float) base_exp / (float) nextb; + if (nextj > 0) + nextjp = (float) job_exp / (float) nextj; sd->status.base_exp += base_exp; if(sd->status.base_exp < 0) @@ -4014,9 +4023,9 @@ int pc_gainexp(struct map_session_data *sd,int base_exp,int job_exp) clif_updatestatus(sd,SP_JOBEXP); - if(battle_config.disp_experience){ + if(battle_config.disp_experience && !sd->noexp){ sprintf(output, - "Experienced Gained Base:%d Job:%d",base_exp,job_exp); + "Experienced Gained Base:%d (%.2f%%) Job:%d (%.2f%%)",base_exp,nextbp*(float)100,job_exp,nextjp*(float)100); clif_disp_onlyself(sd,output,strlen(output)); } @@ -7300,3 +7309,29 @@ int do_init_pc(void) { return 0; } + +/*========================================== + * sd - father dstsd - mother jasd - child + */ +int pc_adoption(struct map_session_data *sd,struct map_session_data *dstsd, struct map_session_data *jasd) +{ + int j; + if(sd == NULL || dstsd == NULL || jasd == NULL || sd->status.partner_id <= 0 || dstsd->status.partner_id <= 0 || sd->status.partner_id != dstsd->status.char_id || dstsd->status.partner_id != sd->status.char_id || sd->status.child > 0 || dstsd->status.child || jasd->status.father > 0 || jasd->status.mother > 0) + return -1; + jasd->status.father=sd->status.char_id; + jasd->status.mother=dstsd->status.char_id; + sd->status.child=jasd->status.char_id; + dstsd->status.child=jasd->status.char_id; + for (j=0; j < MAX_INVENTORY; j++) { + if(jasd->status.inventory[j].nameid>0 && jasd->status.inventory[j].equip!=0) + pc_unequipitem(jasd, j, 3); + } + if (pc_jobchange(jasd, 4023, 0) == 0) + clif_displaymessage(jasd->fd, msg_table[12]); // Your job has been changed. + else { + clif_displaymessage(jasd->fd, msg_table[155]); // Impossible to change your job. + return -1; + } + return 0; +} + diff --git a/src/map/pc.h b/src/map/pc.h index 8c4f96529..1e5b3408f 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -166,6 +166,7 @@ int pc_calc_pvprank_timer(int tid,unsigned int tick,int id,int data); int pc_ismarried(struct map_session_data *sd); int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd); int pc_divorce(struct map_session_data *sd); +int pc_adoption(struct map_session_data *sd,struct map_session_data *dstsd,struct map_session_data *jasd); struct map_session_data *pc_get_partner(struct map_session_data *sd); int pc_set_gm_level(int account_id, int level); void pc_setstand(struct map_session_data *sd); diff --git a/src/map/pet.c b/src/map/pet.c index 553f64044..0a8a44e10 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -1587,10 +1587,11 @@ int read_petdb() { FILE *fp; char line[1024]; - int i; + int nameid,i; int j=0; int lines; char *filename[]={"db/pet_db.txt","db/pet_db2.txt"}; + char *str[32],*p,*np; memset(pet_db,0,sizeof(pet_db)); for(i=0;i<2;i++){ @@ -1604,8 +1605,6 @@ int read_petdb() lines = 0; while(fgets(line,1020,fp)){ lines++; - int nameid,i; - char *str[32],*p,*np; if(line[0] == '/' && line[1] == '/') continue; diff --git a/src/map/script.c b/src/map/script.c index a732f7bc4..d7d5f433e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -6980,6 +6980,7 @@ int buildin_cardscnt(struct script_state *st) struct map_session_data *sd; int i, k, id = 1; int ret = 0; + int index, type; sd = script_rid2sd(st); @@ -6988,7 +6989,6 @@ int buildin_cardscnt(struct script_state *st) if (id <= 0) continue; - int index, type; index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus] if(index < 0) continue; diff --git a/src/map/skill.c b/src/map/skill.c index 131e8324b..a6b7887f4 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1909,7 +1909,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id,int data ) case BA_FROSTJOKE: /* 寒いジョ?ク */ case DC_SCREAM: /* スクリ?ム */ - range=15; //視界全? + range=battle_config.area_size; //視界全? map_foreachinarea(skill_frostjoke_scream,src->m,src->x-range,src->y-range, src->x+range,src->y+range,0,src,skl->skill_id,skl->skill_lv,tick); break; @@ -5205,7 +5205,7 @@ struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid, case DC_DONTFORGETME: /* 私を忘れないで… */ if(src->type == BL_PC) val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1; - val2 = ((status_get_str(src)/20)&0xffff)<<16; + val2 = ((status_get_dex(src)/20)&0xffff)<<16; val2 |= (status_get_agi(src)/10)&0xffff; break; case BA_POEMBRAGI: /* ブラギの詩 */ -- cgit v1.2.3-70-g09d2