void t_script_give_spell::do_action(t_hero* hero) const { g_mute_icons = true; if ( (hero == NULL) || (hero->in_spellbook(get_spell())) ) return; g_mute_icons = !hero->learn_spell(get_spell()); }
/** * Cast a spell from a book. */ void textui_obj_cast(void) { int item; int spell; const char *verb = magic_desc[mp_ptr->spell_realm][SPELL_VERB]; char q[80]; char s[80]; if (mp_ptr->spell_realm == REALM_NONE) { msg("You cannot read books!"); return; } strnfmt(q, sizeof(q), "Use which %s?", magic_desc[mp_ptr->spell_realm][BOOK_NOUN]); strnfmt(s, sizeof(s), " You have no %ss that you can use.", magic_desc[mp_ptr->spell_realm][BOOK_LACK]); item_tester_hook = obj_can_cast_from; if (!get_item(&item, q, s, CMD_CAST, (USE_INVEN | USE_FLOOR))) return; /* Track the object kind */ track_object(item); /* Ask for a spell */ spell = get_spell(object_from_item_idx(item), verb, spell_okay_to_cast); if (spell >= 0) { cmd_insert(CMD_CAST); cmd_set_arg_choice(cmd_get_top(), 0, spell); } }
/** * Study a book to gain a new spell */ void textui_obj_study(void) { int item; char q[80]; char s[80]; if (mp_ptr->spell_realm == REALM_NONE) { msg("You cannot read books!"); return; } strnfmt(q, sizeof(q), "Study which %s?", magic_desc[mp_ptr->spell_realm][BOOK_NOUN]); strnfmt(s, sizeof(s), " You have no %ss that you can study.", magic_desc[mp_ptr->spell_realm][BOOK_LACK]); item_tester_hook = obj_can_study; if (!get_item(&item, q, s, CMD_STUDY_BOOK, (USE_INVEN | USE_FLOOR))) return; track_object(item); handle_stuff(p_ptr); if (mp_ptr->spell_book != TV_PRAYER_BOOK) { int spell = get_spell(object_from_item_idx(item), "study", spell_okay_to_study); if (spell >= 0) { cmd_insert(CMD_STUDY_SPELL); cmd_set_arg_choice(cmd_get_top(), 0, spell); } } else { cmd_insert(CMD_STUDY_BOOK); cmd_set_arg_item(cmd_get_top(), 0, item); } }
/* * Pray a spell */ void do_pray(int book) { int j; /* Ask for a spell, allow cancel */ if (!get_spell(&j, "prayer", "Pray which prayer? ", &book, FALSE)) return; /* Additional */ if (!do_cast_xtra(book, j)) return; /* Tell the server */ Send_pray(book, j); }
/* * This function should be used anytime you are not 100% sure that you have * a valid spell/skill number. A typical for() loop would not need to use * this because you can guarantee > 0 and <= TOP_SPELL_DEFINE. */ char *spell_name(int num) { struct spell_info_type *sptr; sptr = get_spell(num, __FILE__, __FUNCTION__); if (num > 0 && num <= top_of_spellt) return (sptr->name); else if (num == -1) return ("UNUSED"); else return ("UNDEFINED"); }
/* * Cast a spell */ void do_cast(int book) { int j; /* Ask for a spell, allow cancel */ if (!get_spell(&j, "spell", "Cast which spell? ", &book, FALSE)) return; /* Additional */ if (!do_cast_xtra(book, j)) return; /* Tell the server */ Send_cast(book, j); }
/* * Use a ghost ability */ void do_ghost(void) { int book = 10; /* HACK -- USE BOOK 10 -- */ int j; /* Ask for an ability, allow cancel */ if (!get_spell(&j, "power", "Use which power? ", &book, FALSE)) return; /* Additional */ if (!do_cast_xtra(book, j)) return; /* Tell the server */ Send_ghost(j); }
/* * Study a book to gain a new spell/prayer */ void do_study(int book) { int j; /* Mage -- Learn a selected spell */ if (c_info[pclass].spell_book == TV_MAGIC_BOOK) { /* Ask for a spell, allow cancel */ if (!get_spell(&j, "spell", "Study which spell? ", &book, FALSE)) return; } /* Priest -- Learn random spell */ else j = -1; /* Tell the server */ /* Note that if we are a priest, the server ignores the spell parameter */ Send_gain(book, j); }
void creature_cast_spell(creature_t* creature, creature_t* target) { bool did_cast = false; // TODO: Cast specific spells depending on circumstance. spell_id spellid = creature->spellbook.spell[random(0, creature->spellbook.number_of_spells - 1)]; const spell_t* spell = &get_spell(spellid); if ((spell->flag & SF_MISSILE)|| (spell->flag & SF_RAY)) { if (in_range_of_spell(spell, creature, target->pos.x, target->pos.y) && !_is_ally_in_ray(creature, target)) { cast_spell(spell, creature, target->pos.x, target->pos.y); did_cast = true; } } else if (spell->range == RANGE_SELF) { cast_spell(spell, creature, creature->pos.x, creature->pos.y); did_cast = true; } else { if (!_other_spells(spell, creature, target, did_cast)) { // Smite targeted if (in_range_of_spell(spell, creature, target->pos.x, target->pos.y)) { cast_spell(spell, creature, target->pos.x, target->pos.y); did_cast = true; } } } if (!did_cast) { creature->step_toward(target->pos.x, target->pos.y, target); } }
/* pick the context menu options appropiate for the item */ int context_menu_object(const object_type *o_ptr, const int slot) { menu_type *m; region r; int selected; char *labels; char header[120]; textblock *tb; region area = { 0, 0, 0, 0 }; bool allowed = TRUE; int mode = OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG; unsigned char cmdkey; m = menu_dynamic_new(); if (!m || !o_ptr) { return 0; } object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_BASE); labels = string_make(lower_case); m->selections = labels; /* 'I' is used for inspect in both keymaps. */ menu_dynamic_add_label(m, "Inspect", 'I', MENU_VALUE_INSPECT, labels); if (obj_can_browse(o_ptr)) { if (obj_can_cast_from(o_ptr) && player_can_cast(p_ptr, FALSE)) { ADD_LABEL("Cast", CMD_CAST, MN_ROW_VALID); } if (obj_can_study(o_ptr) && player_can_study(p_ptr, FALSE)) { cmd_code study_cmd = player_has(PF_CHOOSE_SPELLS) ? CMD_STUDY_SPELL : CMD_STUDY_BOOK; /* Hack - Use the STUDY_BOOK command key so that we get the correct command key. */ cmdkey = cmd_lookup_key_unktrl(CMD_STUDY_BOOK, mode); menu_dynamic_add_label(m, "Study", cmdkey, study_cmd, labels); } if (player_can_read(p_ptr, FALSE)) { ADD_LABEL("Browse", CMD_BROWSE_SPELL, MN_ROW_VALID); } } else if (obj_is_useable(o_ptr)) { if (obj_is_wand(o_ptr)) { menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Aim", CMD_USE_WAND, valid); } else if (obj_is_rod(o_ptr)) { menu_row_validity_t valid = (obj_can_zap(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Zap", CMD_USE_ROD, valid); } else if (obj_is_staff(o_ptr)) { menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Use", CMD_USE_STAFF, valid); } else if (obj_is_scroll(o_ptr)) { menu_row_validity_t valid = (player_can_read(p_ptr, FALSE)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Read", CMD_READ_SCROLL, valid); } else if (obj_is_potion(o_ptr)) { ADD_LABEL("Quaff", CMD_QUAFF, MN_ROW_VALID); } else if (obj_is_food(o_ptr)) { ADD_LABEL("Eat", CMD_EAT, MN_ROW_VALID); } else if (obj_is_activatable(o_ptr)) { menu_row_validity_t valid = (slot >= INVEN_WIELD && obj_can_activate(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Activate", CMD_ACTIVATE, valid); } else if (obj_can_fire(o_ptr)) { ADD_LABEL("Fire", CMD_FIRE, MN_ROW_VALID); } else { ADD_LABEL("Use", CMD_USE_ANY, MN_ROW_VALID); } } if (obj_can_refill(o_ptr)) { ADD_LABEL("Refill", CMD_REFILL, MN_ROW_VALID); } if (slot >= INVEN_WIELD && obj_can_takeoff(o_ptr)) { ADD_LABEL("Take off", CMD_TAKEOFF, MN_ROW_VALID); } else if (slot < INVEN_WIELD && obj_can_wear(o_ptr)) { //if (obj_is_armor(o_ptr)) { // menu_dynamic_add(m, "Wear", 2); //} else { // menu_dynamic_add(m, "Wield", 2); //} ADD_LABEL("Equip", CMD_WIELD, MN_ROW_VALID); } if (slot >= 0) { if (!store_in_store || cave_shopnum(cave, p_ptr->py, p_ptr->px) == STORE_HOME) { ADD_LABEL("Drop", CMD_DROP, MN_ROW_VALID); if (o_ptr->number > 1) { /* 'D' is used for squelch in rogue keymap, so we'll just swap letters. */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? 'D' : 'k'; menu_dynamic_add_label(m, "Drop All", cmdkey, MENU_VALUE_DROP_ALL, labels); } } } else { menu_row_validity_t valid = (inven_carry_okay(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Pick up", CMD_PICKUP, valid); } ADD_LABEL("Throw", CMD_THROW, MN_ROW_VALID); ADD_LABEL("Inscribe", CMD_INSCRIBE, MN_ROW_VALID); if (obj_has_inscrip(o_ptr)) { ADD_LABEL("Uninscribe", CMD_UNINSCRIBE, MN_ROW_VALID); } ADD_LABEL( (object_is_squelched(o_ptr) ? "Unignore" : "Ignore"), CMD_DESTROY, MN_ROW_VALID); /* work out display region */ r.width = (int)menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */ r.col = Term->wid - r.width - 1; r.row = 1; r.page_rows = m->count; area.width = -(r.width + 2); /* Hack -- no flush needed */ msg_flag = FALSE; screen_save(); /* Display info */ tb = object_info(o_ptr, OINFO_NONE); object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL); textui_textblock_place(tb, area, format("%s", header)); textblock_free(tb); menu_layout(m, &r); region_erase_bordered(&r); prt(format("(Enter to select, ESC) Command for %s:", header), 0, 0); selected = menu_dynamic_select(m); menu_dynamic_free(m); string_free(labels); screen_load(); cmdkey = cmd_lookup_key(selected, mode); switch (selected) { case -1: /* User cancelled the menu. */ return 3; case MENU_VALUE_INSPECT: /* copied from textui_obj_examine */ /* Display info */ tb = object_info(o_ptr, OINFO_NONE); object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL); textui_textblock_show(tb, area, format("%s", header)); textblock_free(tb); return 2; case MENU_VALUE_DROP_ALL: /* Drop entire stack with confirmation. */ if (get_check(format("Drop %s? ", header))) { cmd_insert(store_in_store ? CMD_STASH : CMD_DROP); cmd_set_arg_item(cmd_get_top(), 0, slot); cmd_set_arg_number(cmd_get_top(), 1, o_ptr->number); } return 1; case CMD_STUDY_SPELL: /* Hack - Use the STUDY_BOOK command key so that get_item_allow() works properly. */ cmdkey = cmd_lookup_key(CMD_STUDY_BOOK, mode); /* Fall through. */ case CMD_BROWSE_SPELL: case CMD_STUDY_BOOK: case CMD_CAST: case CMD_DESTROY: case CMD_WIELD: case CMD_TAKEOFF: case CMD_INSCRIBE: case CMD_UNINSCRIBE: case CMD_PICKUP: case CMD_DROP: case CMD_REFILL: case CMD_THROW: case CMD_USE_WAND: case CMD_USE_ROD: case CMD_USE_STAFF: case CMD_READ_SCROLL: case CMD_QUAFF: case CMD_EAT: case CMD_ACTIVATE: case CMD_FIRE: case CMD_USE_ANY: /* Check for inscriptions that trigger confirmation. */ allowed = key_confirm_command(cmdkey) && get_item_allow(slot, cmdkey, selected, FALSE); break; default: /* Invalid command; prevent anything from happening. */ bell("Invalid context menu command."); allowed = FALSE; break; } if (!allowed) return 1; if (selected == CMD_DESTROY) { /* squelch or unsquelch the item */ textui_cmd_destroy_menu(slot); } else if (selected == CMD_BROWSE_SPELL) { /* browse a spellbook */ /* copied from textui_spell_browse */ textui_book_browse(o_ptr); return 2; } else if (selected == CMD_STUDY_SPELL) { /* study a spell book */ /* copied from textui_obj_study */ int spell = get_spell(o_ptr, "study", spell_okay_to_study); if (spell >= 0) { cmd_insert(CMD_STUDY_SPELL); cmd_set_arg_choice(cmd_get_top(), 0, spell); } } else if (selected == CMD_CAST) { if (obj_can_browse(o_ptr)) { /* copied from textui_obj_cast */ const char *verb = ((p_ptr->class->spell_book == TV_MAGIC_BOOK) ? "cast" : "recite"); int spell = get_spell(o_ptr, verb, spell_okay_to_cast); if (spell >= 0) { cmd_insert(CMD_CAST); cmd_set_arg_choice(cmd_get_top(), 0, spell); } } } else {
/* * Eat some food (from the pack or floor) */ void do_cmd_eat_food(void) { int item, ident, lev; /* Must be true to let us cancel */ bool cancel = TRUE; object_type *o_ptr; cptr q, s; int power; /* Restrict choices to food */ item_tester_tval = TV_FOOD; /* Get an item */ q = "Eat which item? "; s = "You have nothing to eat."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_FEATU))) return; /* Get the feature */ if (item >= INVEN_TOTAL+1) { object_type object_type_body; o_ptr = &object_type_body; if (!make_feat(o_ptr, cave_feat[p_ptr->py][p_ptr->px])) return; } /* Get the item (in the pack) */ else if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Sound */ sound(MSG_EAT); /* Take a (partial) turn */ if ((variant_fast_floor) && (item < 0)) p_ptr->energy_use = 50; else if ((variant_fast_equip) && (item >= INVEN_WIELD)) p_ptr->energy_use = 50; else p_ptr->energy_use = 100; /* Identity not known yet */ ident = FALSE; /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Get food effect */ get_spell(&power, "use", o_ptr, FALSE); /* Paranoia */ if (power < 0) return; /* Apply food effect */ if (process_spell_eaten(power,0,&cancel)) ident = TRUE; /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* We have tried it */ object_tried(o_ptr); /* The player is now aware of the object */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); }
void t_script_give_spell::add_icons(t_basic_dialog* dialog) const { if (g_mute_icons == false) dialog->add_spell(get_spell()); }
void mag_objectmagic(struct char_data *ch, struct obj_data *obj, char *argument) { int i, k; struct char_data *tch = NULL, *next_tch; struct obj_data *tobj = NULL; if (!magic_enabled) return; one_argument(argument, arg); k = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tch, &tobj); switch (GET_OBJ_TYPE(obj)) { case ITEM_STAFF: act("You tap $p three times on the ground.", FALSE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, 0, TO_ROOM); else act("$n taps $p three times on the ground.", FALSE, ch, obj, 0, TO_ROOM); if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char("It seems powerless.\r\n", ch); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); } else { GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); /* Level to cast spell at. */ k = GET_OBJ_VAL(obj, 0) ? GET_OBJ_VAL(obj, 0) : DEFAULT_STAFF_LVL; /* * Problem : Area/mass spells on staves can cause crashes. * Solution: Remove the special nature of area/mass spells on staves. * Problem : People like that behavior. * Solution: We special case the area/mass spells here. */ if (HAS_SPELL_ROUTINE(get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), MAG_MASSES | MAG_AREAS)) { for (i = 0, tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) i++; while (i-- > 0) call_magic(ch, NULL, NULL, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), k, CAST_STAFF, 0); } else { for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) { next_tch = tch->next_in_room; if (ch != tch) call_magic(ch, tch, NULL, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), k, CAST_STAFF, 0); } } } break; case ITEM_WAND: if (k == FIND_CHAR_ROOM) { if (tch == ch) { act("You point $p at yourself.", FALSE, ch, obj, 0, TO_CHAR); act("$n points $p at $mself.", FALSE, ch, obj, 0, TO_ROOM); } else { act("You point $p at $N.", FALSE, ch, obj, tch, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tch, TO_ROOM); else act("$n points $p at $N.", TRUE, ch, obj, tch, TO_ROOM); } } else if (tobj != NULL) { act("You point $p at $P.", FALSE, ch, obj, tobj, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tobj, TO_ROOM); else act("$n points $p at $P.", TRUE, ch, obj, tobj, TO_ROOM); } else if (IS_SET(get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__)->routines, MAG_AREAS | MAG_MASSES)) { /* Wands with area spells don't need to be pointed. */ act("You point $p outward.", FALSE, ch, obj, NULL, TO_CHAR); act("$n points $p outward.", TRUE, ch, obj, NULL, TO_ROOM); } else { act("At what should $p be pointed?", FALSE, ch, obj, NULL, TO_CHAR); return; } if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char("It seems powerless.\r\n", ch); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); return; } GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); if (GET_OBJ_VAL(obj, 0)) call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_WAND, 0); else call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), DEFAULT_WAND_LVL, CAST_WAND, 0); break; case ITEM_SCROLL: if (*arg) { if (!k) { act("There is nothing to here to affect with $p.", FALSE, ch, obj, NULL, TO_CHAR); return; } } else tch = ch; act("You recite $p which dissolves.", TRUE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n recites $p.", FALSE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, i), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_SCROLL, 0) <= 0) break; if (obj != NULL) extract_obj(obj); break; case ITEM_POTION: tch = ch; act("You quaff $p.", FALSE, ch, obj, NULL, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n quaffs $p.", TRUE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, ch, NULL, get_spell(GET_OBJ_VAL(obj, i), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_POTION, 0) <= 0) break; if (obj != NULL) extract_obj(obj); break; case ITEM_SPELLBOOK: tch = ch; act("You study $p.", FALSE, ch, obj, NULL, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n studies $p.", TRUE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) { if (GET_OBJ_VAL(obj, i) < 0) break; if (GET_SKILL(ch, GET_OBJ_VAL(obj, i)) < 1) SET_SKILL(ch, GET_OBJ_VAL(obj, i), GET_OBJ_VAL(obj, 0)); } if (obj != NULL) extract_obj(obj); break; default: extended_mudlog(NRM, SYSL_BUGS, TRUE, "Unknown object_type %d in mag_objectmagic.", GET_OBJ_TYPE(obj)); break; } }
void instance::on_cast_spell(const Event& inEvt) { if (!inEvt.hasProperty("Spell")) { Event evt(inEvt); reject(evt); return; } // find the spell object Spell* lSpell; try { lSpell = get_spell(convertTo<int>(inEvt.getProperty("Spell"))); } catch (invalid_uid& e) { // reject the event log_->errorStream() << "couldn't find requested Spell with id " << inEvt.getProperty("Spell"); Event evt(inEvt); reject(evt); return; } Entity* lCaster = lSpell->getCaster(); assert(lCaster && lSpell); log_->debugStream() << "spell cast: " << lSpell->getUID() << "#" << lSpell->getName(); log_->debugStream() << "caster: " << lCaster->getUID() << "#" << lCaster->getName(); // allow only ALL or CASTING spells to be cast by active puppets if (lSpell->getPhase() != BLOCKING && active_puppet_->getUID() != lCaster->getOwner()->getUID()) { Event evt(inEvt); return reject(evt); } // blocking spells can only be cast when the active is not the caster else if (lSpell->getPhase() == BLOCKING && active_puppet_->getUID() == lCaster->getOwner()->getUID()) { Event evt(inEvt); return reject(evt); } Entity* lTarget = 0; if (inEvt.hasProperty("T")) { try { // is the target a puppet? lTarget = get_puppet(convertTo<int>(inEvt.getProperty("T"))).get(); log_->debugStream() << "target: " << lTarget->getUID() << "#" << lTarget->getName(); } catch (invalid_uid& e) { try { // a unit? lTarget = get_unit(convertTo<int>(inEvt.getProperty("T"))); log_->debugStream() << "target: " << lTarget->getUID() << "#" << lTarget->getName(); } catch (invalid_uid& e) { // invalid UID log_->errorStream() << "couldn't find spell target with id " << inEvt.getProperty("T"); Event evt(inEvt); reject(evt); return; } } assert(lTarget); lSpell->setTarget(lTarget); } else { // if the spell requires a target, it must be given #ifdef PARANOID assert(!lSpell->requiresTarget()); #else // gracefully reject the event if (lSpell->requiresTarget()) { log_->errorStream() << "an invalid spell request#" << lSpell->getUID() << "; target is required but not given"; Event e(inEvt); return reject(e); } #endif // otherwise, the spell's target is the caster itself lSpell->setTarget(lCaster); } // verify the caster having enough resources to cast the spell { bool valid = true; if (lCaster->getRank() == PUPPET) { if (lSpell->getCostWP() > ((Puppet*)lCaster)->getWP()) valid = valid && false; // heroes can't have less than 1 channel if (lSpell->getCostChannels() >= ((Puppet*)lCaster)->getChannels()) valid = valid && false; } if (lSpell->getCostHP() > lCaster->getHP()) valid = valid && false; if (!valid) { if (lCaster->getRank() == PUPPET) { Puppet* tCaster = (Puppet*)lCaster; log_->errorStream() << "caster" << tCaster->getUID() << " failed the resources requirements of the spell" << lSpell->getUID() << " : \t " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels() << " vs " << tCaster->getWP() << ":" << tCaster->getHP() << ":" << tCaster->getChannels(); } Event e(inEvt); return reject(e); } } // prepare the response event Event resp(inEvt); resp.setProperty("Spell", lSpell->getUID()); resp.setProperty("C", lSpell->getCaster()->getUID()); if (lSpell->requiresTarget()) resp.setProperty("T", lSpell->getTarget()->getUID()); // dispatch to Lua /*lua_getfield(lua_, LUA_GLOBALSINDEX, "process_spell"); if(!lua_isfunction(lua_, 1)) { log_->errorStream() << "could not find Lua event processor!"; lua_pop(lua_,1); Event e(inEvt); return reject(e); } log_->debugStream() << "\t things are looking good, passing to lua: " << ", cost: " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels(); tolua_pushusertype(lua_,(void*)lCaster,"Pixy::Entity"); tolua_pushusertype(lua_,(void*)lTarget,"Pixy::Entity"); tolua_pushusertype(lua_,(void*)lSpell,"Pixy::Spell"); tolua_pushusertype(lua_,(void*)&inEvt,"Pixy::Event"); try { lua_call(lua_, 4, 1); } catch (std::exception& e) { log_->errorStream() << "Lua Handler: " << e.what(); } bool result = lua_toboolean(lua_, lua_gettop(lua_)); lua_remove(lua_, lua_gettop(lua_));*/ bool result = pass_to_lua( "Spells.onCastSpell", 3, "Pixy::Entity", lCaster, "Pixy::Entity", lTarget, "Pixy::Spell", lSpell); log_->debugStream() << "\t back from lua: " << ", cost: " << lSpell->getCostWP() << ":" << lSpell->getCostHP() << ":" << lSpell->getCostChannels(); // if the spell cast was successful, we first broadcast the command to // the clients, then detach the spell from the caster, and finally // we apply any resource changes to the caster and broadcast them too if (result) { // broadcast the CastSpell event to players, confirming it { resp.Feedback = EventFeedback::Ok; broadcast(resp); } // update the caster stats and broadcast them { Event evt(EventUID::Unassigned, EventFeedback::Ok); evt.setProperty("UID", lCaster->getUID()); if (lCaster->getRank() == PUPPET) { Puppet* tCaster = static_cast<Puppet*>(lCaster); evt.UID = EventUID::UpdatePuppet; // apply WP cost, if any if (lSpell->getCostWP() > 0) { tCaster->setWP(tCaster->getWP() - lSpell->getCostWP()); evt.setProperty("WP", tCaster->getWP()); log_->debugStream() << tCaster->getName() << " paid " << lSpell->getCostWP() << " wp," << " and now has " << tCaster->getWP() << " wp."; } // apply the Channels cost, if any if (lSpell->getCostChannels() > 0) { tCaster->setChannels(tCaster->getChannels() - lSpell->getCostChannels()); evt.setProperty("Channels", tCaster->getChannels()); log_->debugStream() << tCaster->getName() << " paid " << lSpell->getCostChannels() << " channels," << " and now has " << tCaster->getChannels() << " channels."; } } else evt.UID = EventUID::UpdateUnit; // apply HP cost, if any if (lSpell->getCostHP() > 0) { lCaster->setHP(lCaster->getHP() - lSpell->getCostHP()); evt.setProperty("HP", lCaster->getHP()); log_->debugStream() << lCaster->getName() << " paid " << lSpell->getCostHP() << " hp," << " and now has " << lCaster->getHP() << " hp."; } broadcast(evt); } // don't delete the spell object if it's a buff lCaster->detachSpell(lSpell->getUID(), lSpell->getDuration() == 0); } else { // we reject the request //Event e(inEvt); resp.Feedback = EventFeedback::Error; return reject(resp); } lSpell = 0; lCaster = 0; lTarget = 0; //return result; }
/* * Handle monster hitting a real trap. */ void mon_hit_trap(int m_idx, int y, int x) { feature_type *f_ptr; monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int feat = cave_feat[y][x]; bool fear; /* Option */ if (!variant_hit_traps) return; /* Hack --- don't activate unknown invisible traps */ if (cave_feat[y][x] == FEAT_INVIS) return; /* Get feature */ f_ptr = &f_info[cave_feat[y][x]]; /* Hack --- trapped doors */ /* XXX XXX Dangerous */ while (!(f_ptr->spell) && !(f_ptr->blow.method) && (f_ptr->flags1 & (FF1_TRAP))) { pick_trap(y,x); /* Error */ if (cave_feat[y][x] == feat) break; feat = cave_feat[y][x]; /* Get feature */ f_ptr = &f_info[feat]; } /* Use covered or bridged if necessary */ if ((f_ptr->flags2 & (FF2_COVERED)) || (f_ptr->flags2 & (FF2_BRIDGED))) { f_ptr = &f_info[f_ptr->mimic]; } /* Hack -- monster falls onto trap */ if ((m_ptr->fy!=y)|| (m_ptr->fx !=x)) { /* Move monster */ monster_swap(m_ptr->fy, m_ptr->fx, y, x); } /* Apply the object */ if ((cave_o_idx[y][x]) && (f_ptr->flags1 & (FF1_HIT_TRAP))) { object_type *o_ptr = &o_list[cave_o_idx[y][x]]; char o_name[80]; int power = 0; switch (o_ptr->tval) { case TV_BOW: { object_type *j_ptr; u32b f1,f2,f3; int i, shots = 1; /* Get bow */ j_ptr = o_ptr; /* Get bow flags */ object_flags(o_ptr,&f1,&f2,&f3); /* Apply extra shots */ if (f1 & (TR1_SHOTS)) shots += j_ptr->pval; /* Test for hit */ for (i = 0; i < shots; i++) { if (j_ptr->next_o_idx) { int ammo = j_ptr->next_o_idx; object_type *i_ptr; object_type object_type_body; /* Use ammo instead of bow */ o_ptr = &o_list[ammo]; /* Describe ammo */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0); if ((ammo) && (test_hit_fire((j_ptr->to_h + o_ptr->to_h)* BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac * (r_ptr->flags2 & (RF2_ARMOR) ? 2 : 1), TRUE))) { int k, mult; switch (j_ptr->sval) { case SV_SLING: case SV_SHORT_BOW: mult = 2; break; case SV_LONG_BOW: case SV_LIGHT_XBOW: mult = 3; break; case SV_HEAVY_XBOW: mult = 4; break; default: mult = 1; break; } /* Apply extra might */ if (f1 & (TR1_MIGHT)) mult += j_ptr->pval; k = damroll(o_ptr->dd, o_ptr->ds); k *= mult; k = tot_dam_aux(o_ptr, k, m_ptr); k = critical_shot(o_ptr->weight, o_ptr->to_h + j_ptr->to_h, k); k += o_ptr->to_d + j_ptr->to_d; /* No negative damage */ if (k < 0) k = 0; /* Trap description */ msg_format("%^s hits you.",o_name); /* Damage, check for fear and death */ (void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL); } else { /* Trap description */ msg_format("%^s narrowly misses you.",o_name); } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Drop nearby - some chance of breakage */ drop_near(i_ptr,y,x,breakage_chance(i_ptr)); /* Decrease the item */ floor_item_increase(ammo, -1); floor_item_optimize(ammo); break; } else { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); } } } case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_HAFTED: case TV_SWORD: case TV_POLEARM: { object_type *i_ptr; object_type object_type_body; /* Describe ammo */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0); /* Test for hit */ if (test_hit_norm(o_ptr->to_h * BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac, TRUE)) { int k; k = damroll(o_ptr->dd, o_ptr->ds); k = tot_dam_aux(o_ptr, k, m_ptr); k = critical_norm(o_ptr->weight, o_ptr->to_h, k); k += o_ptr->to_d; /* Armour reduces total damage */ k -= (k * ((p_ptr->ac < 150) ? p_ptr->ac : 150) / 250); /* No negative damage */ if (k < 0) k = 0; /* Trap description */ msg_format("%^s hits you.",o_name); /* Damage, check for fear and death */ (void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL); } else { /* Trap description */ msg_format("%^s narrowly misses you.",o_name); } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Drop nearby - some chance of breakage */ drop_near(i_ptr,y,x,breakage_chance(i_ptr)); /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); break; } case TV_WAND: case TV_STAFF: { if (o_ptr->pval > 0) { /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* XXX Hack -- new unstacking code */ o_ptr->stackc++; /* No spare charges */ if (o_ptr->stackc >= o_ptr->number) { /* Use a charge off the stack */ o_ptr->pval--; /* Reset the stack count */ o_ptr->stackc = 0; } /* XXX Hack -- unstack if necessary */ if ((o_ptr->number > 1) && ((!variant_pval_stacks) || ((!object_known_p(o_ptr) && (o_ptr->pval == 2) && (o_ptr->stackc > 1)) || (!object_known_p(o_ptr) && (rand_int(o_ptr->number) <= o_ptr->stackc) && (o_ptr->stackc != 1) && (o_ptr->pval > 2))))) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Reset stack counter */ i_ptr->stackc = 0; /* Unstack the used item */ o_ptr->number--; /* Reduce the charges on the new item */ if (o_ptr->stackc > 1) { i_ptr->pval-=2; o_ptr->stackc--; } else if (!o_ptr->stackc) { i_ptr->pval--; o_ptr->pval++; o_ptr->stackc = o_ptr->number-1; } (void)floor_carry(y,x,i_ptr); } } else { /* Disarm if runs out */ cave_alter_feat(y,x,FS_DISARM); } break; } case TV_ROD: case TV_DRAG_ARMOR: { if (!((o_ptr->timeout) && ((!o_ptr->stackc) || (o_ptr->stackc >= o_ptr->number)))) { int tmpval; /* Store pval */ tmpval = o_ptr->timeout; /* Time rod out */ o_ptr->timeout = o_ptr->pval; /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* Has a power */ /* Hack -- check if we are stacking rods */ if ((o_ptr->timeout > 0) && (!(tmpval) || stack_force_times)) { /* Hack -- one more rod charging */ if (o_ptr->timeout) o_ptr->stackc++; /* Reset stack count */ if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0; /* Hack -- always use maximum timeout */ if (tmpval > o_ptr->timeout) o_ptr->timeout = tmpval; } /* XXX Hack -- unstack if necessary */ if ((o_ptr->number > 1) && (o_ptr->timeout > 0)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Clear stack counter */ i_ptr->stackc = 0; /* Restore "charge" */ o_ptr->timeout = tmpval; /* Unstack the used item */ o_ptr->number--; /* Reset the stack if required */ if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0; (void)floor_carry(y,x,i_ptr); } } break; } case TV_POTION: case TV_SCROLL: case TV_FLASK: case TV_FOOD: { /* Hack -- boring food */ if ((o_ptr->tval == TV_FOOD) && (o_ptr->sval >= SV_FOOD_MIN_FOOD)) { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); } else { /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); } break; } case TV_RUNESTONE: { u32b runes = p_ptr->cur_runes; int num = 0; s16b book[26]; /* Hack -- use current rune */ p_ptr->cur_runes = (2 << (o_ptr->sval-1)); /* Fill the book with spells */ fill_book(o_ptr,book,&num); /* Unhack */ p_ptr->cur_runes = runes; /* Get a power */ power = book[rand_int(num)]; /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); break; } default: { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); break; } } /* Has a power */ if (power > 0) { spell_type *s_ptr = &s_info[power]; int ap_cnt; /* Object is used */ if (k_info[o_ptr->k_idx].used < MAX_SHORT) k_info[o_ptr->k_idx].used++; /* Scan through all four blows */ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++) { int damage = 0; /* Extract the attack infomation */ int effect = s_ptr->blow[ap_cnt].effect; int method = s_ptr->blow[ap_cnt].method; int d_dice = s_ptr->blow[ap_cnt].d_dice; int d_side = s_ptr->blow[ap_cnt].d_side; int d_plus = s_ptr->blow[ap_cnt].d_plus; /* Hack -- no more attacks */ if (!method) break; /* Mega hack -- dispel evil/undead objects */ if (!d_side) { d_plus += 25 * d_dice; } /* Roll out the damage */ if ((d_dice) && (d_side)) { damage = damroll(d_dice, d_side) + d_plus; } else { damage = d_plus; } (void)project_m(0,0,y,x,damage, effect); (void)project_f(0,0,y,x,damage, effect); } } } /* Regular traps */ else { if (f_ptr->spell) { make_attack_spell_aux(0,y,x,f_ptr->spell); } else if (f_ptr->blow.method) { int damage = damroll(f_ptr->blow.d_side,f_ptr->blow.d_dice); /* Apply the blow */ project_m(0, 0, y, x, damage, f_ptr->blow.effect); } /* Get feature */ f_ptr = &f_info[cave_feat[p_ptr->py][p_ptr->px]]; if (f_ptr->flags1 & (FF1_HIT_TRAP)) { /* Modify the location hit by the trap */ cave_alter_feat(y,x,FS_HIT_TRAP); } else if (f_ptr->flags1 & (FF1_SECRET)) { /* Discover */ cave_alter_feat(y,x,FS_SECRET); } } }