/** * Saves changed achievements for a character. * @param[in] char_id character identifier. * @param[out] cp pointer to loaded achievements. * @param[in] p pointer to map-sent character achievements. * @return number of achievements saved. */ static int inter_achievement_tosql(int char_id, struct char_achievements *cp, const struct char_achievements *p) { StringBuf buf; int i = 0, rows = 0; nullpo_ret(cp); nullpo_ret(p); Assert_ret(char_id > 0); StrBuf->Init(&buf); StrBuf->Printf(&buf, "REPLACE INTO `%s` (`char_id`, `ach_id`, `completed_at`, `rewarded_at`", char_achievement_db); for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; i++) StrBuf->Printf(&buf, ", `obj_%d`", i); StrBuf->AppendStr(&buf, ") VALUES "); for (i = 0; i < VECTOR_LENGTH(*p); i++) { int j = 0; bool save = false; struct achievement *pa = &VECTOR_INDEX(*p, i), *cpa = NULL; ARR_FIND(0, VECTOR_LENGTH(*cp), j, ((cpa = &VECTOR_INDEX(*cp, j)) && cpa->id == pa->id)); if (j == VECTOR_LENGTH(*cp)) save = true; else if (memcmp(cpa, pa, sizeof(struct achievement)) != 0) save = true; if (save) { StrBuf->Printf(&buf, "%s('%d', '%d', '%"PRId64"', '%"PRId64"'", rows ?", ":"", char_id, pa->id, (int64)pa->completed_at, (int64)pa->rewarded_at); for (j = 0; j < MAX_ACHIEVEMENT_OBJECTIVES; j++) StrBuf->Printf(&buf, ", '%d'", pa->objective[j]); StrBuf->AppendStr(&buf, ")"); rows++; } } if (rows > 0 && SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) { Sql_ShowDebug(inter->sql_handle); StrBuf->Destroy(&buf); // Destroy the buffer. return 0; } // Destroy the buffer. StrBuf->Destroy(&buf); if (rows) { ShowInfo("achievements saved for char %d (total: %d, saved: %d)\n", char_id, VECTOR_LENGTH(*p), rows); /* Sync with inter-db acheivements. */ VECTOR_CLEAR(*cp); VECTOR_ENSURE(*cp, VECTOR_LENGTH(*p), 1); VECTOR_PUSHARRAY(*cp, VECTOR_DATA(*p), VECTOR_LENGTH(*p)); } return rows; }
/** * Retrieves all achievements of a character. * @param[in] char_id character identifier. * @param[out] cp pointer to character achievements structure. * @return true on success, false on failure. */ static bool inter_achievement_fromsql(int char_id, struct char_achievements *cp) { StringBuf buf; char *data; int i = 0, num_rows = 0; nullpo_ret(cp); Assert_ret(char_id > 0); // char_achievements (`char_id`, `ach_id`, `completed_at`, `rewarded_at`, `obj_0`, `obj_2`, ...`obj_9`) StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `ach_id`, `completed_at`, `rewarded_at`"); for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; i++) StrBuf->Printf(&buf, ", `obj_%d`", i); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id` = '%d' ORDER BY `ach_id`", char_achievement_db, char_id); if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) { Sql_ShowDebug(inter->sql_handle); StrBuf->Destroy(&buf); return false; } VECTOR_CLEAR(*cp); if ((num_rows = (int) SQL->NumRows(inter->sql_handle)) != 0) { int j = 0; VECTOR_ENSURE(*cp, num_rows, 1); for (i = 0; i < num_rows && SQL_SUCCESS == SQL->NextRow(inter->sql_handle); i++) { struct achievement t_ach = { 0 }; SQL->GetData(inter->sql_handle, 0, &data, NULL); t_ach.id = atoi(data); SQL->GetData(inter->sql_handle, 1, &data, NULL); t_ach.completed_at = atoi(data); SQL->GetData(inter->sql_handle, 2, &data, NULL); t_ach.rewarded_at = atoi(data); /* Objectives */ for (j = 0; j < MAX_ACHIEVEMENT_OBJECTIVES; j++) { SQL->GetData(inter->sql_handle, j + 3, &data, NULL); t_ach.objective[j] = atoi(data); } /* Add Entry */ VECTOR_PUSH(*cp, t_ach); } } SQL->FreeResult(inter->sql_handle); StrBuf->Destroy(&buf); if (num_rows > 0) ShowInfo("achievements loaded for char %d (total: %d)\n", char_id, num_rows); return true; }
//Party map update notification int mapif_party_membermoved(struct party *p, int idx) { unsigned char buf[20]; nullpo_ret(p); Assert_ret(idx >= 0 && idx < MAX_PARTY); WBUFW(buf,0) = 0x3825; WBUFL(buf,2) = p->party_id; WBUFL(buf,6) = p->member[idx].account_id; WBUFL(buf,10) = p->member[idx].char_id; WBUFW(buf,14) = p->member[idx].map; WBUFB(buf,16) = p->member[idx].online; WBUFW(buf,17) = p->member[idx].lv; mapif->sendall(buf, 19); return 0; }
/** * Map iterator subroutine to update quest objectives for a party after killing a monster. * * @see map_foreachinrange * @param ap Argument list, expecting: * int Party ID * int Mob ID */ int quest_update_objective_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; int party_id = va_arg(ap, int); int mob_id = va_arg(ap, int); nullpo_ret(bl); Assert_ret(bl->type == BL_PC); sd = BL_UCAST(BL_PC, bl); if( !sd->avail_quests ) return 0; if( sd->status.party_id != party_id ) return 0; quest->update_objective(sd, mob_id); return 1; }
int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type) { struct pet_data *pd; int rate; nullpo_ret(sd); pd = sd->pd; Assert_ret(pd->msd == 0 || pd->msd->pd == pd); if( bl == NULL || bl->type != BL_MOB || bl->prev == NULL || pd->pet.intimate < battle_config.pet_support_min_friendly || pd->pet.hungry < 1 || pd->pet.class_ == status->get_class(bl)) return 0; if( pd->bl.m != bl->m || !check_distance_bl(&pd->bl, bl, pd->db->range2)) return 0; if (!status->check_skilluse(&pd->bl, bl, 0, 0)) return 0; if(!type) { rate = pd->petDB->attack_rate; rate = rate * pd->rate_fix/1000; if(pd->petDB->attack_rate > 0 && rate <= 0) rate = 1; } else { rate = pd->petDB->defence_attack_rate; rate = rate * pd->rate_fix/1000; if(pd->petDB->defence_attack_rate > 0 && rate <= 0) rate = 1; } if(rnd()%10000 < rate) { if(pd->target_id == 0 || rnd()%10000 < pd->petDB->change_target_rate) pd->target_id = bl->id; } return 0; }
// Save party to mysql int inter_party_tosql(struct party *p, int flag, int index) { // 'party' ('party_id','name','exp','item','leader_id','leader_char') char esc_name[NAME_LENGTH*2+1];// escaped party name int party_id; if( p == NULL || p->party_id == 0 ) return 0; Assert_ret(index >= 0 && index < MAX_PARTY); party_id = p->party_id; #ifdef NOISY ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); #endif SQL->EscapeStringLen(inter->sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); if( flag & PS_BREAK ) {// Break the party // we'll skip name-checking and just reset everyone with the same party id [celest] if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) Sql_ShowDebug(inter->sql_handle); if( SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) Sql_ShowDebug(inter->sql_handle); //Remove from memory idb_remove(inter_party->db, party_id); return 1; } if( flag & PS_CREATE ) {// Create party if( SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `%s` " "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " "VALUES ('%s', '%d', '%d', '%d', '%d')", party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) { Sql_ShowDebug(inter->sql_handle); return 0; } party_id = p->party_id = (int)SQL->LastInsertId(inter->sql_handle); } if( flag & PS_BASIC ) {// Update party info. if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", party_db, esc_name, p->exp, p->item, party_id) ) Sql_ShowDebug(inter->sql_handle); } if( flag & PS_LEADER ) {// Update leader if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) Sql_ShowDebug(inter->sql_handle); } if( flag & PS_ADDMEMBER ) {// Add one party member. if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) Sql_ShowDebug(inter->sql_handle); } if( flag & PS_DELMEMBER ) {// Remove one party member. if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) Sql_ShowDebug(inter->sql_handle); } if( save_log ) ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); return 1; }
/** * Handler called whenever a global message is spoken in a NPC's area */ int npc_chat_sub(struct block_list* bl, va_list ap) { struct npc_data *nd = NULL; struct npc_parse *npcParse = NULL; char *msg; int len, i; struct map_session_data* sd; struct npc_label_list* lst; struct pcrematch_set* pcreset; struct pcrematch_entry* e; nullpo_ret(bl); Assert_ret(bl->type == BL_NPC); nd = BL_UCAST(BL_NPC, bl); npcParse = nd->chatdb; // Not interested in anything you might have to say... if (npcParse == NULL || npcParse->active == NULL) return 0; msg = va_arg(ap,char*); len = va_arg(ap,int); sd = va_arg(ap,struct map_session_data *); // iterate across all active sets for (pcreset = npcParse->active; pcreset != NULL; pcreset = pcreset->next) { // n across all patterns in that set for (e = pcreset->head; e != NULL; e = e->next) { int offsets[2*10 + 10]; // 1/3 reserved for temp space required by pcre_exec // perform pattern match int r = libpcre->exec(e->pcre_, e->pcre_extra_, msg, len, 0, 0, offsets, ARRAYLENGTH(offsets)); if (r > 0) { // save out the matched strings for (i = 0; i < r; i++) { char var[6], val[255]; snprintf(var, sizeof(var), "$@p%i$", i); libpcre->copy_substring(msg, offsets, r, i, val, sizeof(val)); script->set_var(sd, var, val); } // find the target label.. this sucks.. lst = nd->u.scr.label_list; ARR_FIND(0, nd->u.scr.label_list_num, i, strncmp(lst[i].name, e->label, sizeof(lst[i].name)) == 0); if (i == nd->u.scr.label_list_num) { ShowWarning("npc_chat_sub: Nao foi possivel localizar a label: %s\n", e->label); return 0; } // run the npc script script->run_npc(nd->u.scr.script,lst[i].pos,sd->bl.id,nd->bl.id); return 0; } } } return 0; }