int set_title(string str) { if ( this_body() != this_object() ) error("invalid attempt to set a title\n"); if ( str && strsrch(str, "$N") == -1 ) error("bad title -- needs to contain $N\n"); if ( !str ) title = sprintf("%s the title-less.", capitalize(query_name())); else title = replace_string(str,"$N", capitalize(query_name())); title += "%^RESET%^"; }
// look up a player name (name->ID) in the database // if realname!=NULL, it is set to the database representation // of the name just looked up (use to get propper capitalization). // returns 0 for unknown, -1 for no player with that name and >0 for ID int lookup_name(char *name,char *realname) { int n; unsigned int ID; char *ptr; // spaces and punctuation in text keys confuse mysql. sucks. for (ptr=name; *ptr; ptr++) { if (!isalpha(*ptr)) return -1; } if (strlen(name)>38) return -1; if (strlen(name)<2) return -1; if (multi) pthread_mutex_lock(&mutex); for (n=0; n<MAXLOOK; n++) { if (lookup[n].created+TICKS*60*60<ticker) continue; // dont use entries older than one hour if (!strcasecmp(lookup[n].name,name)) break; } if (n==MAXLOOK) { if (multi) pthread_mutex_unlock(&mutex); query_name(name); return 0; } if (realname) strcpy(realname,lookup[n].name); ID=lookup[n].ID; if (multi) pthread_mutex_unlock(&mutex); return ID; }
void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec, struct work_record *work) { struct nmb_name nmbname; /* Only do this if we are using a WINS server. */ if(we_are_a_wins_client() == False) { if( DEBUGLVL( 10 ) ) { dbgtext( "announce_and_sync_with_domain_master_browser:\n" ); dbgtext( "Ignoring, as we are not a WINS client.\n" ); } return; } make_nmb_name(&nmbname,work->work_group,0x1b); /* First, query for the WORKGROUP<1b> name from the WINS server. */ query_name(unicast_subnet, nmbname.name, nmbname.name_type, find_domain_master_name_query_success, find_domain_master_name_query_fail, NULL); }
/** Send a query to look up the address for a name. * @param[in] query Callback information. * @param[in] name Hostname to look up. * @param[in] request DNS lookup structure (may be NULL). * @param[in] type Preferred request type. */ static void do_query_name(dns_callback_f callback, void *ctx, const char *name, struct reslist *request, int type) { char host_name[HOSTLEN + 1]; ircd_strncpy(host_name, name, HOSTLEN); add_local_domain(host_name, HOSTLEN); if (request == NULL) { request = make_request(callback, ctx); DupString(request->name, host_name); #ifdef IPV6 if (type != T_A) request->state = REQ_AAAA; else #endif request->state = REQ_A; } request->type = type; Debug((DEBUG_DNS, "Requesting DNS %s %s as %p", (request->state == REQ_AAAA ? "AAAA" : "A"), host_name, request)); query_name(host_name, C_IN, type, request); }
state_t & state_t::time_limit( duration_t timeout, const state_t & state_to_switch ) { if( duration_t::zero() == timeout ) SO_5_THROW_EXCEPTION( rc_invalid_time_limit_for_state, "zero can't be used as time limit for state '" + query_name() ); // Old time limit must be dropped if it exists. drop_time_limit(); m_time_limit.reset( new time_limit_t{ timeout, state_to_switch } ); // If this state is active then new time limit must be activated. if( is_active() ) so_5::details::do_with_rollback_on_exception( [&] { m_time_limit->set_up_limit_for_agent( *m_target_agent, *this ); }, [&] { // Time limit must be dropped because it is not activated // for the current state. drop_time_limit(); } ); return *this; }
void check_master_browser_exists(time_t t) { static time_t lastrun=0; struct subnet_record *subrec; const char *workgroup_name = lp_workgroup(); if (!lastrun) lastrun = t; if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60))) return; lastrun = t; dump_workgroups(False); for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) { if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work)) { /* Do a name query for the local master browser on this net. */ query_name( subrec, work->work_group, 0x1d, check_for_master_browser_success, check_for_master_browser_fail, NULL); } } } }
void collect_all_workgroup_names_from_wins_server(time_t t) { static time_t lastrun = 0; struct work_record *work; /* Only do this if we are using a WINS server. */ if(we_are_a_wins_client() == False) return; /* Check to see if we are a domain master browser on the unicast subnet. */ if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) { if( DEBUGLVL( 0 ) ) { dbgtext( "collect_all_workgroup_names_from_wins_server:\n" ); dbgtext( "Cannot find my workgroup %s ", lp_workgroup() ); dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name ); } return; } if(!AM_DOMAIN_MASTER_BROWSER(work)) return; if ((lastrun != 0) && (t < lastrun + (15 * 60))) return; lastrun = t; /* First, query for the *<1b> name from the WINS server. */ query_name(unicast_subnet, "*", 0x1b, find_all_domain_master_names_query_success, find_all_domain_master_names_query_fail, NULL); }
/** * Returns adjusted damage based on the caster. * @param caster Who is casting. * @param spell_type Spell ID we're adjusting. * @param base_dam Base damage. * @return Adjusted damage. */ int SP_level_dam_adjust(object *caster, int spell_type, int base_dam) { float tmp_add; int dam_adj, level = SK_level(caster); /* Sanity check */ if (level <= 0 || level > MAXLEVEL) { LOG(llevBug, "SP_level_dam_adjust(): object %s has invalid level %d\n", query_name(caster, NULL), level); if (level <= 0) { level = 1; } else { level = MAXLEVEL; } } /* get a base damage when we don't have one from caller */ if (base_dam == -1) { base_dam = spells[spell_type].bdam; } if ((tmp_add = LEVEL_DAMAGE(level / 3) - 0.75f) < 0) { tmp_add = 0; } dam_adj = (sint16) ((float) base_dam * (LEVEL_DAMAGE(level) + tmp_add) * PATH_DMG_MULT(caster, find_spell(spell_type))); return dam_adj; }
/** * Causes an object to explode, eg, a firebullet, poison cloud ball, etc. * @param op The object to explode. */ void explode_object(object *op) { tag_t op_tag = op->count; object *tmp; int type; play_sound_map(op->map, op->x, op->y, SOUND_OB_EXPLODE, SOUND_NORMAL); if (op->other_arch == NULL) { LOG(llevBug, "BUG: explode_object(): op %s without other_arch\n", query_name(op, NULL)); remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); return; } tmp = arch_to_object(op->other_arch); type = tmp->stats.sp; if (!type) { type = op->stats.sp; } copy_owner(tmp, op); cast_cone(op, op, 0, spells[type].bdur, type, op->other_arch); hit_map(op, 0, 0); /* remove the firebullet */ if (!was_destroyed(op, op_tag)) { remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); } }
string query_title() { /* ensure the player has a title. set it if none (yet) */ if ( !title ) title = sprintf("%s the title-less", capitalize(query_name())); return title; }
/** * Handles object throwing objects of type "DUST". * @todo This function needs to be rewritten. Works for area effect * spells only now. * @param op Object throwing. * @param throw_ob What to throw. * @param dir Direction to throw into. */ void cast_dust(object *op, object *throw_ob, int dir) { archetype *arch = NULL; if (!(spells[throw_ob->stats.sp].flags & SPELL_DESC_DIRECTION)) { LOG(llevBug, "DEBUG: Warning, dust %s is not AE spell!!\n", query_name(throw_ob, NULL)); return; } if (spells[throw_ob->stats.sp].archname) { arch = find_archetype(spells[throw_ob->stats.sp].archname); } /* Casting POTION 'dusts' is really use_magic_item skill */ if (op->type == PLAYER && throw_ob->type == POTION && !change_skill(op, SK_USE_MAGIC_ITEM)) { return; } if (throw_ob->type == POTION && arch != NULL) { cast_cone(op, throw_ob, dir, 10, throw_ob->stats.sp, arch); } /* dust_effect */ else if ((arch = find_archetype("dust_effect")) != NULL) { cast_cone(op, throw_ob, dir, 1, 0, arch); } /* Problem occured! */ else { LOG(llevBug, "BUG: cast_dust() can't find an archetype to use!\n"); } if (op->type == PLAYER && arch) { new_draw_info_format(NDI_UNIQUE, op, "You cast %s.", query_name(throw_ob, NULL)); } if (!QUERY_FLAG(throw_ob, FLAG_REMOVED)) { destruct_ob(throw_ob); } }
int on_drop( object player ) { if( !::on_drop(player) ) return 0; if( query_held() ) { set_held( 0 ); player->msg_local( "~CACT~Name ~verbtake off ~poss " + query_name() + " and ~verbdrop it.~CDEF" ); return MOVE_SILENCE_FLAG | MOVE_OK_FLAG; } else return MOVE_OK_FLAG; }
int on_give( object giver, object receiver ) { if( !::on_give(giver, receiver) ) return 0; if( query_held() ) { set_held( 0 ); giver->msg_local( "~CACT~Name ~verbtake off ~poss " + query_name() + " and ~verbgive it to " + receiver->query_specific() + ".~CDEF" ); return MOVE_SILENCE_FLAG | MOVE_OK_FLAG; } else return MOVE_OK_FLAG; }
/** * Check if an item op can be put into a sack. If pl exists then tell * a player the reason of failure. * @param pl Player object. * @param sack The sack. * @param op The object to check. * @param nrof Number of objects we want to put in. * @return 1 if the object will fit, 0 if it will not. */ int sack_can_hold(object *pl, object *sack, object *op, int nrof) { char buf[MAX_BUF]; buf[0] = '\0'; if (!QUERY_FLAG(sack, FLAG_APPLIED)) { snprintf(buf, sizeof(buf), "The %s is not active.", query_name(sack, NULL)); } if (sack == op) { snprintf(buf, sizeof(buf), "You can't put the %s into itself.", query_name(sack, NULL)); } if ((sack->race && (sack->sub_type & 1) != ST1_CONTAINER_CORPSE) && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) { snprintf(buf, sizeof(buf), "You can put only %s into the %s.", sack->race, query_name(sack, NULL)); } if (op->type == KEY && sack->slaying && op->slaying) { snprintf(buf, sizeof(buf), "You don't want put the key into %s.", query_name(sack, NULL)); } if (sack->weight_limit && sack->carrying + (sint32) ((float) (((nrof ? nrof : 1) * op->weight) + op->carrying) * sack->weapon_speed) > (sint32) sack->weight_limit) { snprintf(buf, sizeof(buf), "That won't fit in the %s!", query_name(sack, NULL)); } if (buf[0]) { if (pl) { new_draw_info(NDI_UNIQUE, pl, buf); } return 0; } return 1; }
/** Send a query to look up the name for an address. * @param[in] query Callback information. * @param[in] addr Address to look up. * @param[in] request DNS lookup structure (may be NULL). */ static void do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *addr, struct reslist *request) { char ipbuf[128]; const unsigned char *cp; if (irc_in_addr_is_ipv4(addr)) { cp = (const unsigned char*)&addr->in6_16[6]; ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.", (unsigned int)(cp[3]), (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0])); } else { const char *intarpa; if (request != NULL && request->state == REQ_INT) intarpa = "int"; else intarpa = "arpa"; cp = (const unsigned char *)&addr->in6_16[0]; ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.", (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4), (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4), (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4), (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4), (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4), (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4), (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4), (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4), (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4), (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4), (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4), (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4), (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4), (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4), (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4), (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa); } if (request == NULL) { request = make_request(callback, ctx); request->state= REQ_PTR; request->type = T_PTR; memcpy(&request->addr, addr, sizeof(request->addr)); request->name = (char *)MyMalloc(HOSTLEN + 1); } Debug((DEBUG_DNS, "Requesting DNS PTR %s as %p", ipbuf, request)); query_name(ipbuf, C_IN, T_PTR, request); }
main(int argc, char *argv[]){ /** Check the number of parameters */ if (argc < 5) { /** Tell the user how to run the program */ cerr << "Usage: " << argv[0] << " token encrows results num_threads" << endl; return 1; } mr_init_threading(); PFC pfc(AES_SECURITY); SecureSelect *db=NULL; int m=0; string query_name(argv[1]); string enctable_name(argv[2]); string results_name(argv[3]); int num_threads = atoi(argv[4]); db = new SecureSelect(&pfc,pfc.order()); if (!ifstream(query_name+"_ptok")){ cout << "Query file doesn't exist" << endl; return 0; } if (!ifstream(enctable_name+"_enc_msgs")){ cout << "Enctable file doesn't exist" << endl; return 0; } #ifdef VERBOSE int start = getMilliCount(); #endif int res_num = db->ApplyPTokenMT(query_name, enctable_name, results_name, num_threads); //int res_num = db->ApplyPToken(query_name, enctable_name, results_name); #ifdef VERBOSE int milliSecondsElapsed = getMilliSpan(start); cout << "\texec time " << milliSecondsElapsed << endl; #endif if(res_num >=0){ cout << res_num << " result(s) found" << endl; return 1; } else return 0; }
/** * Attempt to apply the object 'below' the player. * * If the player has an open container, we use that for below, otherwise * we use the ground. * @param pl Player. */ void player_apply_below(object *pl) { object *tmp, *next; int floors; if (pl->type != PLAYER) { LOG(llevBug, "BUG: player_apply_below() called for non player object >%s<\n", query_name(pl, NULL)); return; } tmp = pl->below; /* This is perhaps more complicated. However, I want to make sure that * we don't use a corrupt pointer for the next object, so we get the * next object in the stack before applying. This is can only be a * problem if player_apply() has a bug in that it uses the object but does * not return a proper value. */ for (floors = 0; tmp != NULL; tmp = next) { next = tmp->below; if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) { floors++; } /* Process only floor objects after first floor object */ else if (floors > 0) { return; } if (!IS_INVISIBLE(tmp, pl) || QUERY_FLAG(tmp, FLAG_WALK_ON) || QUERY_FLAG(tmp, FLAG_FLY_ON)) { if (player_apply(pl, tmp, 0, 1) == 1) { return; } } /* Process at most two floor objects */ if (floors >= 2) { return; } } }
/** * Player is selling an item. Give money, print appropriate messages. * @param op Object to sell. * @param pl Player. Shouldn't be NULL or non player. * @param value If op is NULL, this value is used instead of using * query_cost(). */ void sell_item(object *op, object *pl, sint64 value) { sint64 i; if (pl == NULL || pl->type != PLAYER) { LOG(llevDebug, "DEBUG: sell_item(): Object other than player tried to sell something.\n"); return; } if (op == NULL) { i = value; } else { i = query_cost(op, pl, F_SELL); } if (!i) { if (op) { new_draw_info_format(NDI_UNIQUE, pl, "We're not interested in %s.", query_name(op, NULL)); } } i = insert_coins(pl, i); if (!op) { return; } if (i != 0) { LOG(llevBug, "BUG: Warning - payment not zero: %d\n", i); } new_draw_info_format(NDI_UNIQUE, pl, "You receive %s for %s.", query_cost_string(op, pl, 1), query_name(op, NULL)); SET_FLAG(op, FLAG_UNPAID); /* Identify the item. Makes any unidentified item sold to unique shop appear identified. */ identify(op); }
/** * Living thing is applying an object. * @param pl ::object causing op to be applied. * @param op ::object being applied. * @param aflag Special (always apply/unapply) flags. Nothing is done * with them in this function - they are passed to apply_special(). * @param quiet If 1, suppresses the "don't know how to apply" and "you * must get it first" messages as needed by player_apply_below(). There * can still be "but you are floating high above the ground" messages. * @retval 0 Player or monster can't apply objects of that type. * @retval 1 Has been applied, or there was an error applying the object. * @retval 2 Objects of that type can't be applied if not in * inventory. */ int player_apply(object *pl, object *op, int aflag, int quiet) { int tmp; if (op->env == NULL && QUERY_FLAG(pl, FLAG_FLYING)) { /* Player is flying and applying object not in inventory */ if (!QUERY_FLAG(pl, FLAG_WIZ) && !QUERY_FLAG(op, FLAG_FLYING) && !QUERY_FLAG(op, FLAG_FLY_ON)) { new_draw_info(NDI_UNIQUE, pl, "But you are floating high above the ground!"); return 0; } } if (op->type != PLAYER && QUERY_FLAG(op, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) { play_sound_map(pl->map, pl->x, pl->y, SOUND_OB_EVAPORATE, SOUND_NORMAL); new_draw_info(NDI_UNIQUE, pl, "The object disappears in a puff of smoke!"); new_draw_info(NDI_UNIQUE, pl, "It must have been an illusion."); remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); return 1; } tmp = manual_apply(pl, op, aflag); if (!quiet) { if (tmp == 0) { new_draw_info_format(NDI_UNIQUE, pl, "I don't know how to apply the %s.", query_name(op, NULL)); } else if (tmp == 2) { new_draw_info_format(NDI_UNIQUE, pl, "You must get it first!\n"); } } return tmp; }
/** * Make player forget a spell. * @param op Player object to make forget the spell. * @param spell ID of the spell. */ void do_forget_spell(object *op, int spell) { object *tmp; int i; if (op->type != PLAYER) { LOG(llevBug, "BUG: do_forget_spell(): Not a player: %s (%d).\n", query_name(op, NULL), spell); return; } if (!check_spell_known(op, spell)) { LOG(llevBug, "BUG: do_forget_spell(): Spell %d not known.\n", spell); return; } play_sound_player_only(CONTR(op), SOUND_LOSE_SOME,SOUND_NORMAL,0,0); new_draw_info_format(NDI_UNIQUE, op, "You lose knowledge of %s.", spells[spell].name); send_spelllist_cmd(op, spells[spell].name, SPLIST_MODE_REMOVE); tmp = find_special_prayer_mark(op, spell); if (tmp) { remove_ob(tmp); } for (i = 0; i < CONTR(op)->nrofknownspells; i++) { if (CONTR(op)->known_spells[i] == spell) { CONTR(op)->known_spells[i] = CONTR(op)->known_spells[--CONTR(op)->nrofknownspells]; return; } } LOG(llevBug, "BUG: do_forget_spell(): Couldn't find spell %d.\n", spell); }
const state_t * state_t::actual_state_to_enter() const { const state_t * s = this; while( 0 != s->m_substate_count ) { if( s->m_last_active_substate ) // Note: for states with shallow history m_last_active_substate // can point to composite substate. This substate must be // processed usual way with checking for substate count, presence // of initial substate and so on... s = s->m_last_active_substate; else if( !s->m_initial_substate ) SO_5_THROW_EXCEPTION( rc_no_initial_substate, "there is no initial substate for composite state: " + query_name() ); else s = s->m_initial_substate; } return s; }
/** * Causes cone object 'op' to move a space/hit creatures. * @param op Cone object moving. */ void move_cone(object *op) { int i; tag_t tag; /* If no map then hit_map will crash so just ignore object */ if (!op->map) { LOG(llevBug, "BUG: Tried to move_cone object %s without a map.\n", query_name(op, NULL)); remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); return; } /* Lava saves it's life, but not yours :) */ if (QUERY_FLAG(op, FLAG_LIFESAVE)) { hit_map(op, 0, 0); return; } /* If no owner left, the spell dies out. */ if (get_owner(op) == NULL) { remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); return; } /* Hit map returns 1 if it hits a monster. If it does, set * food to 1, which will stop the cone from progressing. */ tag = op->count; op->stats.food |= hit_map(op, 0, 1); if (was_destroyed(op, tag)) { return; } if ((op->stats.hp -= 2) < 0) { if (op->stats.exp) { op->speed = 0; update_ob_speed(op); op->stats.exp = 0; /* So they will join */ op->stats.sp = 0; } else { remove_ob(op); check_walk_off(op, NULL, MOVE_APPLY_VANISHED); } return; } if (op->stats.food) { return; } op->stats.food = 1; for (i = -1; i < 2; i++) { int x = op->x + freearr_x[absdir(op->stats.sp + i)], y = op->y + freearr_y[absdir(op->stats.sp + i)]; if (ok_to_put_more(op->map, x, y, op)) { object *tmp = arch_to_object(op->arch); copy_owner(tmp, op); /* *very* important - this is the count value of the * *first* object we created with this cone spell. * we use it for identify this spell. Miss this * and ok_to_put_more will allow to create 1000th * in a single tile! */ tmp->weight_limit = op->weight_limit; tmp->x = x, tmp->y = y; tmp->level = op->level; tmp->stats.sp = op->stats.sp, tmp->stats.hp = op->stats.hp + 1; tmp->stats.maxhp = op->stats.maxhp; tmp->stats.dam = op->stats.dam; if (!insert_ob_in_map(tmp, op->map, op, 0)) { return; } if (tmp->other_arch) { cone_drop(tmp); } } } }
/** * Main apply handler. * * Checks for unpaid items before applying. * @param op ::object causing tmp to be applied. * @param tmp ::object being applied. * @param aflag Special (always apply/unapply) flags. Nothing is done * with them in this function - they are passed to apply_special(). * @retval 0 Player or monster can't apply objects of that type. * @retval 1 Has been applied, or there was an error applying the object. * @retval 2 Objects of that type can't be applied if not in * inventory. */ int manual_apply(object *op, object *tmp, int aflag) { if (tmp->head) { tmp = tmp->head; } if (op->type == PLAYER) { CONTR(op)->praying = 0; } if (QUERY_FLAG(tmp, FLAG_UNPAID) && !QUERY_FLAG(tmp, FLAG_APPLIED)) { if (op->type == PLAYER) { new_draw_info(NDI_UNIQUE, op, "You should pay for it first."); return 1; } /* Monsters just skip unpaid items */ else { return 0; } } /* Monsters must not apply random chests, nor magic_mouths with a counter */ if (op->type != PLAYER && tmp->type == TREASURE) { return 0; } /* Trigger the APPLY event */ if (!(aflag & AP_NO_EVENT) && trigger_event(EVENT_APPLY, op, tmp, NULL, NULL, aflag, 0, 0, SCRIPT_FIX_ACTIVATOR)) { return 1; } aflag &= ~AP_NO_EVENT; /* Control apply by controling a set exp object level or player exp level */ if (tmp->item_level) { int tmp_lev; if (tmp->item_skill) { tmp_lev = find_skill_exp_level(op, tmp->item_skill); } else { tmp_lev = op->level; } if (tmp->item_level > tmp_lev) { new_draw_info(NDI_UNIQUE, op, "The item level is too high to apply."); return 1; } } switch (tmp->type) { case HOLY_ALTAR: new_draw_info_format(NDI_UNIQUE, op, "You touch the %s.", tmp->name); if (change_skill(op, SK_PRAYING)) { pray_at_altar(op, tmp); } else { new_draw_info(NDI_UNIQUE, op, "Nothing happens. It seems you miss the right skill."); } return 1; break; case HANDLE: new_draw_info(NDI_UNIQUE, op, "You turn the handle."); play_sound_map(op->map, op->x, op->y, SOUND_TURN_HANDLE, SOUND_NORMAL); tmp->value = tmp->value ? 0 : 1; SET_ANIMATION(tmp, ((NUM_ANIMATIONS(tmp) / NUM_FACINGS(tmp)) * tmp->direction) + tmp->value); update_object(tmp, UP_OBJ_FACE); push_button(tmp); return 1; case TRIGGER: if (check_trigger(tmp, op)) { new_draw_info(NDI_UNIQUE, op, "You turn the handle."); play_sound_map(tmp->map, tmp->x, tmp->y, SOUND_TURN_HANDLE, SOUND_NORMAL); } else { new_draw_info(NDI_UNIQUE, op, "The handle doesn't move."); } return 1; case EXIT: if (op->type != PLAYER || !tmp->map) { return 0; } /* If no map path specified, we assume it is the map path of the exit. */ if (!EXIT_PATH(tmp)) { FREE_AND_ADD_REF_HASH(EXIT_PATH(tmp), tmp->map->path); } if (!EXIT_PATH(tmp) || !is_legal_2ways_exit(op, tmp) || (EXIT_Y(tmp) == -1 && EXIT_X(tmp) == -1)) { new_draw_info_format(NDI_UNIQUE, op, "The %s is closed.", query_name(tmp, NULL)); } else { /* Don't display messages for random maps. */ if (tmp->msg && strncmp(EXIT_PATH(tmp), "/!", 2) && strncmp(EXIT_PATH(tmp), "/random/", 8)) { new_draw_info(NDI_NAVY, op, tmp->msg); } enter_exit(op, tmp); } return 1; case SIGN: apply_sign(op, tmp); return 1; case BOOK: if (op->type == PLAYER) { apply_book(op, tmp); return 1; } return 0; case SKILLSCROLL: if (op->type == PLAYER) { apply_skillscroll(op, tmp); return 1; } return 0; case SPELLBOOK: if (op->type == PLAYER) { apply_spellbook(op, tmp); return 1; } return 0; case SCROLL: apply_scroll(op, tmp); return 1; case POTION: (void) apply_potion(op, tmp); return 1; case LIGHT_APPLY: apply_player_light(op, tmp); return 1; case LIGHT_REFILL: apply_player_light_refill(op, tmp); return 1; /* Eneq(@csd.uu.se): Handle apply on containers. */ case CLOSE_CON: if (op->type == PLAYER) { (void) esrv_apply_container(op, tmp->env); } return 1; case CONTAINER: if (op->type == PLAYER) { (void) esrv_apply_container(op, tmp); } return 1; case TREASURE: apply_treasure(op, tmp); return 1; case WEAPON: case ARMOUR: case BOOTS: case GLOVES: case AMULET: case GIRDLE: case BRACERS: case SHIELD: case HELMET: case RING: case CLOAK: case WAND: case ROD: case HORN: case SKILL: case BOW: case SKILL_ITEM: /* Not in inventory */ if (tmp->env != op) { return 2; } (void) apply_special(op, tmp, aflag); return 1; case DRINK: case FOOD: case FLESH: apply_food(op, tmp); return 1; case POISON: apply_poison(op, tmp); return 1; case SAVEBED: if (op->type == PLAYER) { apply_savebed(op); return 1; } return 0; case ARMOUR_IMPROVER: if (op->type == PLAYER) { apply_armour_improver(op, tmp); return 1; } return 0; case WEAPON_IMPROVER: apply_weapon_improver(op, tmp); return 1; case CLOCK: if (op->type == PLAYER) { timeofday_t tod; get_tod(&tod); new_draw_info_format(NDI_UNIQUE, op, "It is %d minute%s past %d o'clock %s", tod.minute + 1, ((tod.minute + 1 < 2) ? "" : "s"), ((tod.hour % (HOURS_PER_DAY / 2) == 0) ? (HOURS_PER_DAY / 2) : ((tod.hour) % (HOURS_PER_DAY / 2))), ((tod.hour >= (HOURS_PER_DAY / 2)) ? "pm" : "am")); return 1; } return 0; case POWER_CRYSTAL: apply_power_crystal(op, tmp); return 1; /* For lighting torches/lanterns/etc */ case LIGHTER: if (op->type == PLAYER) { apply_lighter(op, tmp); return 1; } return 0; /* So the below default case doesn't execute for these objects, * even if they have message. */ case DOOR: return 0; /* Nothing from the above... but show a message if it has one. */ default: if (tmp->msg) { new_draw_info(NDI_UNIQUE, op, tmp->msg); return 1; } return 0; } }
/** * Descends containers looking for unpaid items, and pays for them. * @param pl Player buying the stuff. * @param op Object we are examining. If op has and inventory, we examine * that. Ii there are objects below op, we descend down. * @retval 0 Player still has unpaid items. * @retval 1 Player has paid for everything. */ int get_payment(object *pl, object *op) { char buf[MAX_BUF]; int ret = 1; if (op != NULL && op->inv) { ret = get_payment(pl, op->inv); } if (!ret) { return 0; } if (op != NULL && op->below) { ret = get_payment(pl, op->below); } if (!ret) { return 0; } if (op != NULL && QUERY_FLAG(op, FLAG_UNPAID)) { strncpy(buf, query_cost_string(op, pl, F_BUY), sizeof(buf)); if (!pay_for_item(op, pl)) { sint64 i = query_cost(op, pl, F_BUY) - query_money(pl); CLEAR_FLAG(op, FLAG_UNPAID); new_draw_info_format(NDI_UNIQUE, pl, "You lack %s to buy %s.", cost_string_from_value(i), query_name(op, NULL)); SET_FLAG(op, FLAG_UNPAID); return 0; } else { object *tmp, *c_cont = op->env; tag_t c = op->count; CLEAR_FLAG(op, FLAG_UNPAID); CLEAR_FLAG(op, FLAG_STARTEQUIP); if (pl->type == PLAYER) { new_draw_info_format(NDI_UNIQUE, pl, "You paid %s for %s.", buf, query_name(op, NULL)); } tmp = merge_ob(op, NULL); if (pl->type == PLAYER) { /* It was merged */ if (tmp) { esrv_del_item(CONTR(pl), c, c_cont); op = tmp; } esrv_send_item(pl, op); } } } return 1; }
/** * Remove a player from the game that has been disconnected by logging * out, the socket connection was interrupted, etc. * @param pl The player to remove. */ void remove_ns_dead_player(player *pl) { if (pl == NULL || pl->ob->type == DEAD_OBJECT) { return; } if (pl->state == ST_PLAYING) { /* Trigger the global LOGOUT event */ trigger_global_event(GEVENT_LOGOUT, pl->ob, pl->socket.host); if (!pl->dm_stealth) { new_draw_info_format(NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, NULL, "%s left the game.", query_name(pl->ob, NULL)); } /* If this player is in a party, leave the party */ if (pl->party) { command_party(pl->ob, "leave"); } strncpy(pl->killer, "left", MAX_BUF - 1); hiscore_check(pl->ob, 1); /* Be sure we have closed container when we leave */ container_unlink(pl, NULL); save_player(pl->ob, 0); if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) { leave_map(pl->ob); } if (pl->ob->map) { if (pl->ob->map->in_memory == MAP_IN_MEMORY) { pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map); } pl->ob->map = NULL; } } LOG(llevInfo, "LOGOUT: >%s< from IP %s\n", pl->ob->name, pl->socket.host); /* To avoid problems with inventory window */ pl->ob->type = DEAD_OBJECT; free_player(pl); }
/** * This pays for the item, and takes the proper amount of money off the * player. * @param op Player paying. * @param pouch Container (pouch or player) to remove the coins from. * @param to_pay Required amount. * @return Amount still not paid after using "pouch". */ static sint64 pay_from_container(object *op, object *pouch, sint64 to_pay) { sint64 remain; int count, i; object *tmp, *coin_objs[NUM_COINS], *next, *bank_object = NULL; archetype *at; object *who; (void) op; if (pouch->type != PLAYER && pouch->type != CONTAINER) { return to_pay; } remain = to_pay; for (i = 0; i < NUM_COINS; i++) { coin_objs[i] = NULL; } /* This hunk should remove all the money objects from the player/container */ for (tmp = pouch->inv; tmp; tmp = next) { next = tmp->below; if (tmp->type == MONEY) { for (i = 0; i < NUM_COINS; i++) { if (!strcmp(coins[NUM_COINS - 1 - i], tmp->arch->name) && (tmp->value == tmp->arch->clone.value)) { /* This should not happen, but if it does, just merge * the two. */ if (coin_objs[i] != NULL) { LOG(llevBug, "BUG: pay_from_container(): %s has two money entries of (%s)\n", query_name(pouch, NULL), coins[NUM_COINS - 1 - i]); remove_ob(tmp); coin_objs[i]->nrof += tmp->nrof; esrv_del_item(CONTR(pouch), tmp->count, tmp->env); } else { remove_ob(tmp); if (pouch->type == PLAYER) { esrv_del_item(CONTR(pouch), tmp->count,tmp->env); } coin_objs[i] = tmp; } break; } } if (i == NUM_COINS) { LOG(llevBug, "BUG: pay_from_container(): Did not find string match for %s\n", tmp->arch->name); } } else if (tmp->arch->name == shstr_cons.player_info && tmp->name == shstr_cons.BANK_GENERAL) { bank_object = tmp; } } /* Fill in any gaps in the coin_objs array - needed to make change. */ /* Note that the coin_objs array goes from least value to greatest value */ for (i = 0; i < NUM_COINS; i++) { if (coin_objs[i] == NULL) { at = find_archetype(coins[NUM_COINS - 1 - i]); if (at == NULL) { LOG(llevBug, "BUG: pay_from_container(): Could not find %s archetype", coins[NUM_COINS - 1 - i]); } coin_objs[i] = get_object(); copy_object(&at->clone, coin_objs[i], 0); coin_objs[i]->nrof = 0; } } for (i = 0; i < NUM_COINS; i++) { sint64 num_coins; if ((sint64) (coin_objs[i]->nrof * coin_objs[i]->value) > remain) { num_coins = remain / coin_objs[i]->value; if ((num_coins * coin_objs[i]->value) < remain) { num_coins++; } } else { num_coins = coin_objs[i]->nrof; } if (num_coins > ((sint64) 1 << 31)) { LOG(llevDebug, "DEBUG: pay_from_container(): Money overflow value->nrof: number of coins > 2 ^ 32 (type coin %d)\n", i); num_coins = ((sint64) 1 << 31); } remain -= num_coins * coin_objs[i]->value; coin_objs[i]->nrof -= (uint32) num_coins; /* Now start making change. Start at the coin value * below the one we just did, and work down to * the lowest value. */ count = i - 1; while (remain < 0 && count >= 0) { num_coins = -remain / coin_objs[count]->value; coin_objs[count]->nrof += (uint32) num_coins; remain += num_coins * coin_objs[count]->value; count--; } } /* If there's still some remain, that means we could try to pay from * bank. */ if (bank_object && bank_object->value != 0 && remain != 0 && bank_object->value >= remain) { bank_object->value -= remain; remain = 0; } for (i = 0; i < NUM_COINS; i++) { if (coin_objs[i]->nrof) { object *tmp = insert_ob_in_ob(coin_objs[i], pouch); for (who = pouch; who && who->type != PLAYER && who->env != NULL; who = who->env) { } esrv_send_item(who, tmp); esrv_send_item (who, pouch); esrv_update_item(UPD_WEIGHT, who, pouch); if (pouch->type != PLAYER) { esrv_send_item(who, who); esrv_update_item(UPD_WEIGHT, who, who); } } } return remain; }
/** * Return the price of an item for a character. * @param tmp Object we're querying the price of. * @param who Who is inquiring. Can be NULL, only meaningful if player. * @param flag Combination of @ref F_xxx "F_xxx" flags. * @return The price for the item. */ sint64 query_cost(object *tmp, object *who, int flag) { sint64 val; double diff; int number; int charisma = 11; if ((number = tmp->nrof) == 0) { number = 1; } /* Money is always identified */ if (tmp->type == MONEY) { return (number * tmp->value); } /* Handle identified items */ if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp)) { if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) { return 0; } else { val = tmp->value * number; } } /* This area deals with objects that are not identified, but can be */ else { if (tmp->arch != NULL) { if (flag == F_BUY) { LOG(llevBug, "BUG: query_cost(): Asking for buy-value of unidentified object %s.\n", query_name(tmp, NULL)); val = tmp->arch->clone.value * number; } /* Trying to sell something, or get true value */ else { /* Selling unidentified gems is *always* stupid */ if (tmp->type == GEM || tmp->type == JEWEL || tmp->type == NUGGET || tmp->type == PEARL) { val = number * 3; } /* Don't want to give anything away */ else if (tmp->type == POTION) { val = number * 50; } else { val = number * tmp->arch->clone.value; } } } else { /* No archetype with this object - we generate some dummy values to avoid server break */ LOG(llevBug, "BUG: query_cost(): Have object with no archetype: %s\n", query_name(tmp, NULL)); if (flag == F_BUY) { LOG(llevBug, "BUG: query_cost(): Asking for buy-value of unidentified object without arch.\n"); val = number * 100; } else { val = number * 80; } } } /* Wands will count special. The base value is for a wand with one charge */ if (tmp->type == WAND) { val += (val * tmp->level) * tmp->stats.food; } else if (tmp->type == ROD || tmp->type == HORN || tmp->type == POTION || tmp->type == SCROLL) { val += val * tmp->level; } /* We are done if we only want get the real value */ if (flag == F_TRUE) { return val; } /* First, we adjust charisma for players and count skills in */ if (who != NULL && who->type == PLAYER) { /* Used for SK_BARGAINING modification */ charisma = who->stats.Cha; /* This skill will give us a charisma boost */ if (find_skill(who, SK_BARGAINING)) { charisma += 4; if (charisma > MAX_STAT) { charisma = MAX_STAT; } } } /* Now adjust for sell or buy multiplier */ if (flag == F_BUY) { diff = (double) (1.0 - (double) cha_bonus[charisma]); } else { diff = (double) (0.20 + (double) cha_bonus[charisma]); } val = (val * (long) (1000 * (diff))) / 1000; /* We want to give at least 1 copper for items which have any * value. */ if (val < 1 && tmp->value > 0) { val = 1; } return val; }
/** * Op throws any object toss_item. * @param op Living thing throwing something. * @param toss_item Item thrown. * @param dir Direction to throw. */ void do_throw(object *op, object *toss_item, int dir) { object *left_cont, *throw_ob = toss_item, *left = NULL, *tmp_op; tag_t left_tag; rv_vector range_vector; if (!throw_ob) { if (op->type == PLAYER) { new_draw_info(NDI_UNIQUE, op, "You have nothing to throw."); } return; } if (QUERY_FLAG(throw_ob, FLAG_STARTEQUIP)) { if (op->type == PLAYER) { new_draw_info(NDI_UNIQUE, op, "The gods won't let you throw that."); } return; } if (throw_ob->weight <= 0) { new_draw_info_format(NDI_UNIQUE, op, "You can't throw %s.\n", query_base_name(throw_ob, NULL)); return; } /* These are throwing objects left to the player */ left = throw_ob; left_cont = left->env; left_tag = left->count; /* Sometimes get_split_ob can't split an object (because op->nrof==0?) * and returns NULL. We must use 'left' then */ if ((throw_ob = get_split_ob(throw_ob, 1, NULL, 0)) == NULL) { throw_ob = left; remove_ob(left); check_walk_off(left, NULL, MOVE_APPLY_VANISHED); if (op->type == PLAYER) { esrv_del_item(CONTR(op), left->count, left->env); } } else if (op->type == PLAYER) { if (was_destroyed(left, left_tag)) { esrv_del_item(CONTR(op), left_tag, left_cont); } else { esrv_update_item(UPD_NROF, op, left); } } /* Special case: throwing powdery substances like dust, dirt */ if (QUERY_FLAG(throw_ob, FLAG_DUST)) { cast_dust(op, throw_ob, dir); /* update the shooting speed for the player action timer. * We init the used skill with it - its not calculated here. * cast_dust() can change the used skill... */ if (op->type == PLAYER) { op->chosen_skill->stats.maxsp = throw_ob->last_grace; } return; } /* Targetting throwing */ if (!dir && op->type == PLAYER && OBJECT_VALID(CONTR(op)->target_object, CONTR(op)->target_object_count)) { dir = get_dir_to_target(op, CONTR(op)->target_object, &range_vector); } /* Three things here prevent a throw, you aimed at your feet, you * have no effective throwing strength, or you threw at a wall */ if (!dir || wall(op->map, op->x + freearr_x[dir], op->y + freearr_y[dir])) { /* Bounces off 'wall', and drops to feet */ if (!QUERY_FLAG(throw_ob, FLAG_REMOVED)) { remove_ob(throw_ob); if (check_walk_off(throw_ob, NULL, MOVE_APPLY_MOVE) != CHECK_WALK_OK) { return; } } throw_ob->x = op->x; throw_ob->y = op->y; if (!insert_ob_in_map(throw_ob, op->map, op, 0)) { return; } if (op->type == PLAYER) { if (!dir) { new_draw_info_format(NDI_UNIQUE, op, "You drop %s at the ground.", query_name(throw_ob, NULL)); } else { new_draw_info(NDI_UNIQUE, op, "Something is in the way."); } } return; } set_owner(throw_ob, op); set_owner(throw_ob->inv, op); throw_ob->direction = dir; throw_ob->x = op->x; throw_ob->y = op->y; /* Save original wc and dam */ throw_ob->last_heal = throw_ob->stats.wc; throw_ob->stats.hp = throw_ob->stats.dam; /* Speed */ throw_ob->speed = MIN(1.0f, (speed_bonus[op->stats.Str] + 1.0f) / 1.5f); /* Now we get the wc from the used skill. */ if ((tmp_op = SK_skill(op))) { throw_ob->stats.wc += tmp_op->last_heal; } /* Monsters */ else { throw_ob->stats.wc += 10; } throw_ob->stats.wc_range = op->stats.wc_range; if (QUERY_FLAG(throw_ob, FLAG_IS_THROWN)) { throw_ob->stats.dam += throw_ob->magic; throw_ob->stats.wc += throw_ob->magic; /* Adjust for players */ if (op->type == PLAYER) { op->chosen_skill->stats.maxsp = throw_ob->last_grace; throw_ob->stats.dam = FABS((int) ((float) (throw_ob->stats.dam + dam_bonus[op->stats.Str] / 2) * LEVEL_DAMAGE(SK_level(op)))); throw_ob->stats.wc += thaco_bonus[op->stats.Dex] + SK_level(op); } else { throw_ob->stats.dam = FABS((int) ((float) (throw_ob->stats.dam) * LEVEL_DAMAGE(op->level))); throw_ob->stats.wc += 10 + op->level; } throw_ob->stats.grace = throw_ob->last_sp; throw_ob->stats.maxgrace = 60 + (RANDOM() % 12); /* Only throw objects get directional faces */ if (GET_ANIM_ID(throw_ob) && NUM_ANIMATIONS(throw_ob)) { SET_ANIMATION(throw_ob, (NUM_ANIMATIONS(throw_ob) / NUM_FACINGS(throw_ob)) * dir); } /* Adjust damage with item condition */ throw_ob->stats.dam = (sint16) (((float) throw_ob->stats.dam / 100.0f) * (float) throw_ob->item_condition); } if (throw_ob->stats.dam < 0) { throw_ob->stats.dam = 0; } update_ob_speed(throw_ob); throw_ob->speed_left = 0; SET_MULTI_FLAG(throw_ob, FLAG_FLYING); SET_FLAG(throw_ob, FLAG_FLY_ON); SET_FLAG(throw_ob, FLAG_WALK_ON); play_sound_map(op->map, CMD_SOUND_EFFECT, "throw.ogg", op->x, op->y, 0, 0); /* Trigger the THROW event */ trigger_event(EVENT_THROW, op, throw_ob, NULL, NULL, 0, 0, 0, SCRIPT_FIX_ACTIVATOR); if (insert_ob_in_map(throw_ob, op->map, op, 0)) { move_arrow(throw_ob); } }
/** * Requests an object to throw by tag reported by the client. * * We search for it in the inventory of the owner (you've got to be * carrying something in order to throw it). * * Also checks to see if the object is throwable (ie, not applied, cursed * worn, etc). * @param op Object to search in. * @param tag Tag of the object we're looking for. * @return The found object or NULL. */ object *find_throw_tag(object *op, tag_t tag) { object *tmp; /* Look through the inventory. */ for (tmp = op->inv; tmp; tmp = tmp->below) { /* Can't toss invisible or inv-locked items */ if (IS_SYS_INVISIBLE(tmp) || QUERY_FLAG(tmp, FLAG_INV_LOCKED)) { continue; } if (tmp->count == tag) { break; } } if (!tmp) { return NULL; } if (QUERY_FLAG(tmp, FLAG_APPLIED)) { /* We can't apply throwing stuff like darts, so this must be a * weapon. Skip if not OR when it can't be thrown OR when it is * startequip which can't be dropped. */ if (tmp->type != WEAPON || !QUERY_FLAG(tmp, FLAG_IS_THROWN)) { new_draw_info_format(NDI_UNIQUE, op, "You can't throw %s.", query_base_name(tmp, NULL)); return NULL; } else if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) { new_draw_info(NDI_UNIQUE, op, "You can't throw god-given item!"); return NULL; } /* If cursed or damned, we can't unapply it - no throwing. */ else if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) { new_draw_info_format(NDI_UNIQUE, op, "The %s sticks to your hand!", query_base_name(tmp, NULL)); return NULL; } /* It's a throw hybrid weapon - unapply it. Then we will fire it * after this function returns. */ else { if (apply_special(op, tmp, AP_UNAPPLY | AP_NO_MERGE)) { LOG(llevBug, "BUG: find_throw_ob(): couldn't unapply throwing item %s from %s\n", query_name(tmp, NULL), query_name(op, NULL)); return NULL; } } } else { /* Not weapon nor throwable - no throwing. */ if ((tmp->type != WEAPON && tmp->type != POTION) && !QUERY_FLAG(tmp, FLAG_IS_THROWN)) { new_draw_info_format(NDI_UNIQUE, op, "You can't throw %s.", query_base_name(tmp, NULL)); return NULL; } /* Special message for throw hybrid weapons. */ else if (tmp->type == WEAPON) { new_draw_info_format(NDI_UNIQUE, op, "You must apply the %s first.", query_base_name(tmp, NULL)); return NULL; } } return tmp; }
/** * Apply an object. * * This function doesn't check for unpaid items, but checks other * restrictions. * * Usage example: apply_special(who, op, AP_UNAPPLY | AP_IGNORE_CURSE) * @param who Object using op. It can be a monster. * @param op Object being used. Should be an equipment type item, eg, one * which you put on and keep on for a while, and not something like a * potion or scroll. * @param aflags Flags. * @return 1 if the action could not be completed, 0 on success. */ int apply_special(object *who, object *op, int aflags) { int basic_flag = aflags & AP_BASIC_FLAGS; int tmp_flag = 0, i; object *tmp; char buf[HUGE_BUF]; if (who == NULL) { LOG(llevBug, "BUG: apply_special() from object without environment.\n"); return 1; } /* op is not in inventory */ if (op->env != who) { return 1; } /* Needs to be initialized */ buf[0] = '\0'; if (!QUERY_FLAG(op, FLAG_APPLIED)) { if (!apply_check_item_power(who, op)) { return 1; } } else { /* Always apply, so no reason to unapply */ if (basic_flag == AP_APPLY) { return 0; } if (!(aflags & AP_IGNORE_CURSE) && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))) { new_draw_info_format(NDI_UNIQUE, who, "No matter how hard you try, you just can't remove it!"); return 1; } if (QUERY_FLAG(op, FLAG_PERM_CURSED)) { SET_FLAG(op, FLAG_CURSED); } if (QUERY_FLAG(op, FLAG_PERM_DAMNED)) { SET_FLAG(op, FLAG_DAMNED); } CLEAR_FLAG(op, FLAG_APPLIED); switch (op->type) { case WEAPON: (void) change_abil(who, op); CLEAR_FLAG(who, FLAG_READY_WEAPON); snprintf(buf, sizeof(buf), "You unwield %s.", query_name(op, NULL)); break; /* Allows objects to impart skills */ case SKILL: if (op != who->chosen_skill) { LOG(llevBug, "BUG: apply_special(): applied skill is not chosen skill\n"); } if (who->type == PLAYER) { CONTR(who)->shoottype = range_none; if (!IS_INVISIBLE(op, who)) { /* It's a tool, need to unlink it */ unlink_skill(op); new_draw_info_format(NDI_UNIQUE, who, "You stop using the %s.", query_name(op, NULL)); new_draw_info_format(NDI_UNIQUE, who, "You can no longer use the skill: %s.", skills[op->stats.sp].name); } } (void) change_abil(who, op); who->chosen_skill = NULL; buf[0] = '\0'; break; case ARMOUR: case HELMET: case SHIELD: case RING: case BOOTS: case GLOVES: case AMULET: case GIRDLE: case BRACERS: case CLOAK: change_abil(who, op); snprintf(buf, sizeof(buf), "You unwear %s.", query_name(op, NULL)); break; case BOW: case WAND: case ROD: case HORN: snprintf(buf, sizeof(buf), "You unready %s.", query_name(op, NULL)); if (who->type == PLAYER) { CONTR(who)->shoottype = range_none; } break; default: snprintf(buf, sizeof(buf), "You unapply %s.", query_name(op, NULL)); break; } if (buf[0] != '\0' && who->type == PLAYER) { new_draw_info(NDI_UNIQUE, who, buf); } fix_player(who); if (!(aflags & AP_NO_MERGE)) { tag_t del_tag = op->count; object *cont = op->env; tmp = merge_ob(op, NULL); if (who->type == PLAYER) { /* It was merged */ if (tmp) { esrv_del_item(CONTR(who), del_tag, cont); op = tmp; } esrv_send_item (who, op); } } return 0; } if (basic_flag == AP_UNAPPLY) { return 0; } i = 0; if (op->type == WAND || op->type == ROD || op->type == HORN) { tmp_flag = 1; } /* This goes through and checks to see if the player already has * something of that type applied - if so, unapply it. */ for (tmp = who->inv; tmp != NULL; tmp = tmp->below) { if ((tmp->type == op->type || (tmp_flag && (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN))) && QUERY_FLAG(tmp, FLAG_APPLIED) && tmp != op) { if (tmp->type == RING && !i) { i = 1; } else if (apply_special(who, tmp, 0)) { return 1; } } } if (op->nrof > 1) { tmp = get_split_ob(op, op->nrof - 1, NULL, 0); } else { tmp = NULL; } switch (op->type) { case WEAPON: { if (!QUERY_FLAG(who, FLAG_USE_WEAPON)) { new_draw_info_format(NDI_UNIQUE, who, "You can't use %s.", query_name(op, NULL)); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } if (!check_weapon_power(who, op->last_eat)) { new_draw_info(NDI_UNIQUE, who, "That weapon is too powerful for you to use.\nIt would consume your soul!"); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } if (op->level && (strncmp(op->name, who->name, strlen(who->name)))) { /* If the weapon does not have the name as the character, * can't use it (Ragnarok's sword attempted to be used by * Foo: won't work). */ new_draw_info(NDI_UNIQUE, who, "The weapon does not recognize you as its owner."); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } /* If we have applied a shield, don't allow applying of polearm or two-handed weapons */ if ((op->sub_type >= WEAP_POLE_IMPACT || op->sub_type >= WEAP_2H_IMPACT) && who->type == PLAYER && CONTR(who) && CONTR(who)->equipment[PLAYER_EQUIP_SHIELD]) { new_draw_info(NDI_UNIQUE, who, "You can't wield this weapon and a shield."); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } if (!check_skill_to_apply(who, op)) { if (tmp != NULL) { (void) insert_ob_in_ob(tmp,who); } return 1; } SET_FLAG(op, FLAG_APPLIED); SET_FLAG(who, FLAG_READY_WEAPON); (void) change_abil(who, op); snprintf(buf, sizeof(buf), "You wield %s.", query_name(op, NULL)); break; } case SHIELD: /* Don't allow polearm or two-handed weapons with a shield */ if ((who->type == PLAYER && CONTR(who) && CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]) && (CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]->sub_type >= WEAP_POLE_IMPACT || CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]->sub_type >= WEAP_2H_IMPACT)) { new_draw_info(NDI_UNIQUE, who, "You can't use a shield with your current weapon."); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } case ARMOUR: case HELMET: case BOOTS: case GLOVES: case GIRDLE: case BRACERS: case CLOAK: if (!QUERY_FLAG(who, FLAG_USE_ARMOUR)) { new_draw_info_format(NDI_UNIQUE, who, "You can't use %s.", query_name(op, NULL)); if (tmp != NULL) { (void) insert_ob_in_ob(tmp, who); } return 1; } case RING: case AMULET: SET_FLAG(op, FLAG_APPLIED); (void) change_abil(who, op); snprintf(buf, sizeof(buf), "You wear %s.", query_name(op, NULL)); break; /* This part is needed for skill-tools */ case SKILL: if (who->chosen_skill) { LOG(llevBug, "BUG: apply_special(): can't apply two skills\n"); return 1; } if (who->type == PLAYER) { CONTR(who)->shoottype = range_skill; if (!IS_INVISIBLE(op, who)) { /* for tools */ if (op->exp_obj) { LOG(llevBug, "BUG: apply_special(SKILL): found unapplied tool with experience object\n"); } else { (void) link_player_skill(who, op); } new_draw_info_format(NDI_UNIQUE, who, "You ready %s.", query_name(op, NULL)); new_draw_info_format(NDI_UNIQUE, who, "You can now use the skill: %s.", skills[op->stats.sp].name); } else { send_ready_skill(who, skills[op->stats.sp].name); } } SET_FLAG(op, FLAG_APPLIED); (void) change_abil(who, op); who->chosen_skill = op; buf[0] = '\0'; break; case WAND: case ROD: case HORN: case BOW: if (!check_skill_to_apply(who, op)) { return 1; } SET_FLAG(op, FLAG_APPLIED); new_draw_info_format(NDI_UNIQUE, who, "You ready %s.", query_name(op, NULL)); if (who->type == PLAYER) { if (op->type == BOW) { new_draw_info_format(NDI_UNIQUE, who, "You will now fire %s with %s.", op->race ? op->race : "nothing", query_name(op, NULL)); } else { CONTR(who)->known_spell = (QUERY_FLAG(op, FLAG_BEEN_APPLIED) || QUERY_FLAG(op, FLAG_IDENTIFIED)); } } break; default: snprintf(buf, sizeof(buf), "You apply %s.", query_name(op, NULL)); } if (!QUERY_FLAG(op, FLAG_APPLIED)) { SET_FLAG(op, FLAG_APPLIED); } if (buf[0] != '\0') { new_draw_info(NDI_UNIQUE, who, buf); } if (tmp != NULL) { tmp = insert_ob_in_ob(tmp, who); } fix_player(who); if (op->type != WAND && who->type == PLAYER) { SET_FLAG(op, FLAG_BEEN_APPLIED); } if (QUERY_FLAG(op, FLAG_PERM_CURSED)) { SET_FLAG(op, FLAG_CURSED); } if (QUERY_FLAG(op, FLAG_PERM_DAMNED)) { SET_FLAG(op, FLAG_DAMNED); } if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) { if (who->type == PLAYER) { new_draw_info(NDI_UNIQUE, who, "Oops, it feels deadly cold!"); } } if (who->type == PLAYER) { /* If multiple objects were applied, update both slots */ if (tmp) { esrv_send_item(who, tmp); } esrv_send_item(who, op); } return 0; }