diff options
-rw-r--r-- | spell-language | 21 | ||||
-rw-r--r-- | src/map/magic-interpreter-base.c | 36 | ||||
-rw-r--r-- | src/map/magic-interpreter.h | 5 | ||||
-rw-r--r-- | src/map/magic-stmt.c | 115 | ||||
-rw-r--r-- | src/map/magic.c | 8 | ||||
-rw-r--r-- | src/map/map.c | 131 | ||||
-rw-r--r-- | src/map/map.h | 4 | ||||
-rw-r--r-- | src/map/pc.c | 7 |
8 files changed, 262 insertions, 65 deletions
diff --git a/spell-language b/spell-language index 21a03a9..b87b42d 100644 --- a/spell-language +++ b/spell-language @@ -609,7 +609,6 @@ This section documents the operations API. instances of `item'. As usual, `item' can be either a string name or an item ID. - + aggravate : entity * int * entity -> () aggravate (victim, mode, target) causes the `victim' to mode = 0: attack `target' @@ -624,9 +623,27 @@ This section documents the operations API. + emote : entity * int -> () Issues the specified emotion to the specified entity. - - set_script_variable : entity * string * int -> () + + set_script_variable : entity * string * int -> () Sets a script variable to the specified value + + set_hair_colour : entity * int -> () + Sets the hair colour of the specified entity to the specified + value (must be a PC). + + + set_hair_style : entity * int -> () + Adjusts the hair style of a PC. + + + drop_item : location * (int | string) * int * int -> () + drop_item(place, "name", count, duration) drops `count' items + (where count may be zero) of name "name" at `place'. The items + vanish again after `duration'. + + + drop_item_for : location * (int | string) + * int * int * entity * int -> () + drop_item_for(place, obj, count, duration, owner, delay) works + like drop_item(place, obj, count, duration), except that the item + can only be picked up by `owner' for the next `delay' + milliseconds, modulo pickup rules (spousal pickup, out-of-range). Script API updates: ------------------- diff --git a/src/map/magic-interpreter-base.c b/src/map/magic-interpreter-base.c index 9be6f81..9338c78 100644 --- a/src/map/magic-interpreter-base.c +++ b/src/map/magic-interpreter-base.c @@ -288,14 +288,19 @@ consume_components(character_t *caster, component_t *component) static int -spellguard_can_satisfy(spellguard_check_t *check, character_t *caster, env_t *env) +spellguard_can_satisfy(spellguard_check_t *check, character_t *caster, env_t *env, int *near_miss) { int tick = gettick(); - int retval = (caster->cast_tick <= tick /* Hasn't cast a spell too recently */ - && check->mana <= caster->status.sp - && check_prerequisites(caster, check->catalysts) - && check_prerequisites(caster, check->components)); + int retval = check_prerequisites(caster, check->catalysts); + + if (retval && near_miss) + *near_miss = 1; // close enough! + + retval = retval + && caster->cast_tick <= tick /* Hasn't cast a spell too recently */ + && check->mana <= caster->status.sp + && check_prerequisites(caster, check->components); if (retval) { int casttime = check->casttime; @@ -313,7 +318,7 @@ spellguard_can_satisfy(spellguard_check_t *check, character_t *caster, env_t *en } static effect_set_t * -spellguard_check_sub(spellguard_check_t *check, spellguard_t *guard, character_t *caster, env_t *env) +spellguard_check_sub(spellguard_check_t *check, spellguard_t *guard, character_t *caster, env_t *env, int *near_miss) { if (guard == NULL) return NULL; @@ -342,13 +347,13 @@ spellguard_check_sub(spellguard_check_t *check, spellguard_t *guard, character_t copy_components(&altcheck.catalysts, check->catalysts); copy_components(&altcheck.components, check->components); - retval = spellguard_check_sub(&altcheck, guard->next, caster, env); + retval = spellguard_check_sub(&altcheck, guard->next, caster, env, near_miss); free_components(&altcheck.catalysts); free_components(&altcheck.components); if (retval) return retval; else - return spellguard_check_sub(check, guard->s.s_alt, caster, env); + return spellguard_check_sub(check, guard->s.s_alt, caster, env, near_miss); } case SPELLGUARD_MANA: @@ -360,7 +365,7 @@ spellguard_check_sub(spellguard_check_t *check, spellguard_t *guard, character_t break; case SPELLGUARD_EFFECT: - if (spellguard_can_satisfy(check, caster, env)) + if (spellguard_can_satisfy(check, caster, env, near_miss)) return &guard->s.s_effect; else return NULL; @@ -370,11 +375,11 @@ spellguard_check_sub(spellguard_check_t *check, spellguard_t *guard, character_t return NULL; } - return spellguard_check_sub(check, guard->next, caster, env); + return spellguard_check_sub(check, guard->next, caster, env, near_miss); } static effect_set_t * -check_spellguard(spellguard_t *guard, character_t *caster, env_t *env) +check_spellguard(spellguard_t *guard, character_t *caster, env_t *env, int *near_miss) { spellguard_check_t check; effect_set_t *retval; @@ -382,7 +387,7 @@ check_spellguard(spellguard_t *guard, character_t *caster, env_t *env) check.components = NULL; check.mana = check.casttime = 0; - retval = spellguard_check_sub(&check, guard, caster, env); + retval = spellguard_check_sub(&check, guard, caster, env, near_miss); free_components(&check.catalysts); free_components(&check.components); @@ -396,17 +401,20 @@ check_spellguard(spellguard_t *guard, character_t *caster, env_t *env) effect_set_t * -spell_trigger(spell_t *spell, character_t *caster, env_t *env) +spell_trigger(spell_t *spell, character_t *caster, env_t *env, int *near_miss) { int i; spellguard_t *guard = spell->spellguard; + if (near_miss) + *near_miss = 0; + for (i = 0; i < spell->letdefs_nr; i++) magic_eval(env, &env->vars[spell->letdefs[i].id], spell->letdefs[i].expr); - return check_spellguard(guard, caster, env); + return check_spellguard(guard, caster, env, near_miss); } static void diff --git a/src/map/magic-interpreter.h b/src/map/magic-interpreter.h index 94c32bc..9fc6308 100644 --- a/src/map/magic-interpreter.h +++ b/src/map/magic-interpreter.h @@ -377,8 +377,11 @@ spell_create_env(magic_conf_t *conf, spell_t *spell, character_t *caster, int sp void magic_free_env(env_t *env); +/** + * near_miss is set to nonzero iff the spell only failed due to ephemereal issues (spell delay in effect, out of mana, out of components) + */ effect_set_t * -spell_trigger(spell_t *spell, character_t *caster, env_t *env); +spell_trigger(spell_t *spell, character_t *caster, env_t *env, int *near_miss); invocation_t * spell_instantiate(effect_set_t *effect, env_t *env); diff --git a/src/map/magic-stmt.c b/src/map/magic-stmt.c index 49c75b1..30b79d1 100644 --- a/src/map/magic-stmt.c +++ b/src/map/magic-stmt.c @@ -504,15 +504,47 @@ op_override_attack(env_t *env, int args_nr, val_t *args) return 0; } +static int // ret -1: not a string, ret 1: no such item, ret 0: OK +find_item(val_t *args, int index, struct item *item, int *stackable) +{ + struct item_data *item_data; + int must_add_sequentially; + + if (TY(index) == TY_INT) + item_data = itemdb_exists(ARGINT(index)); + else if (TY(index) == TY_STRING) + item_data = itemdb_searchname(ARGSTR(index)); + else + return -1; + + if (!item_data) + return 1; + + must_add_sequentially = (item_data->type == 4 + || item_data->type == 5 + || item_data->type == 7 + || item_data->type == 8); /* Very elegant. */ + + + if (stackable) + *stackable = !must_add_sequentially; + + memset(item, 0, sizeof(struct item)); + item->nameid = item_data->nameid; + item->identify = 1; + + return 0; +} + +#define GET_ARG_ITEM(index, dest, stackable) switch(find_item(args, index, &dest, &stackable)) { case -1 : return 1; case 1 : return 0; } static int op_create_item(env_t *env, int args_nr, val_t *args) { - struct item_data *item_data; struct item item; entity_t *entity = ARGENTITY(0); character_t *subject; - int must_add_sequentially; + int stackable; int count = ARGINT(2); if (count <= 0) return 0; @@ -522,26 +554,9 @@ op_create_item(env_t *env, int args_nr, val_t *args) else return 0; - if (TY(1) == TY_INT) - item_data = itemdb_exists(ARGINT(1)); - else if (TY(1) == TY_STRING) - item_data = itemdb_searchname(ARGSTR(1)); - else - return 1; - - if (!item_data) - return 0; - - must_add_sequentially = (item_data->type == 4 - || item_data->type == 5 - || item_data->type == 7 - || item_data->type == 8); /* Very elegant. */ - - memset(&item, 0, sizeof(struct item)); - item.nameid = item_data->nameid; - item.identify = 1; + GET_ARG_ITEM(1, item, stackable); - if (must_add_sequentially) + if (!stackable) while (count--) pc_additem(subject, &item, 1); else @@ -709,6 +724,60 @@ op_set_script_variable(env_t *env, int args_nr, val_t *args) } +static int +op_set_hair_colour(env_t *env, int args_nr, val_t *args) +{ + character_t *c = (ETY(0) == BL_PC)? ARGPC(0) : NULL; + + if (!c) + return 1; + + pc_changelook(c, LOOK_HAIR_COLOR, ARGINT(1)); + + return 0; +} + + +static int +op_set_hair_style(env_t *env, int args_nr, val_t *args) +{ + character_t *c = (ETY(0) == BL_PC)? ARGPC(0) : NULL; + + if (!c) + return 1; + + pc_changelook(c, LOOK_HAIR, ARGINT(1)); + + return 0; +} + +static int +op_drop_item_for(env_t *env, int args_nr, val_t *args) +{ + struct item item; + int stackable; + location_t *loc = &ARGLOCATION(0); + int count = ARGINT(2); + int time = ARGINT(3); + character_t *c = ((args_nr > 4) && (ETY(4) == BL_PC))? ARGPC(4) : NULL; + int delay = (args_nr > 5)? ARGINT(5) : 0; + int delaytime[3] = { delay, delay, delay }; + character_t *owners[3] = { c, NULL, NULL }; + + GET_ARG_ITEM(1, item, stackable); + + if (stackable) + map_addflooritem_any(&item, count, loc->m, loc->x, loc->y, + owners, delaytime, + time, 0); + else while (count-- > 0) + map_addflooritem_any(&item, 1, loc->m, loc->x, loc->y, + owners, delaytime, + time, 0); + + return 0; +} + static op_t operations[] = { { "sfx", ".ii", op_sfx }, @@ -729,6 +798,10 @@ static op_t operations[] = { "injure", "eeii", op_injure }, { "emote", "ei", op_emote }, { "set_script_variable", "esi", op_set_script_variable }, + { "set_hair_colour", "ei", op_set_hair_colour }, + { "set_hair_style", "ei", op_set_hair_style }, + { "drop_item", "l.ii", op_drop_item_for }, + { "drop_item_for", "l.iiei", op_drop_item_for }, { NULL, NULL, NULL } }; diff --git a/src/map/magic.c b/src/map/magic.c index 114f74d..7309281 100644 --- a/src/map/magic.c +++ b/src/map/magic.c @@ -76,8 +76,9 @@ magic_message(character_t *caster, free(spell_invocation); if (spell) { + int near_miss; env_t *env = spell_create_env(&magic_conf, spell, caster, power, parameter); - effect_set_t *effects = spell_trigger(spell, caster, env); + effect_set_t *effects = spell_trigger(spell, caster, env, &near_miss); #ifdef DEBUG fprintf(stderr, "Found spell `%s', triggered = %d\n", spell_, effects != NULL); @@ -99,6 +100,11 @@ magic_message(character_t *caster, return (spell->flags & SPELL_FLAG_SILENT)? -1 : 1; } else { magic_free_env(env); + + /* Obscure proper almost-triggered spell */ + if (near_miss) + while (*source_invocation) + *source_invocation++ = '.'; } return 0; } diff --git a/src/map/map.c b/src/map/map.c index 079da90..30b9d78 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -783,15 +783,18 @@ int map_searchrandfreecell(int m,int x,int y,int range) { * item_dataはamount以外をcopyする *------------------------------------------ */ -int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,struct map_session_data *first_sd, - struct map_session_data *second_sd,struct map_session_data *third_sd,int type) { +int map_addflooritem_any(struct item *item_data, int amount, int m, int x, int y, + struct map_session_data **owners, + int *owner_protection, + int lifetime, int dispersal) +{ int xy,r; unsigned int tick; struct flooritem_data *fitem=NULL; nullpo_retr(0, item_data); - if((xy=map_searchrandfreecell(m,x,y,1))<0) + if((xy=map_searchrandfreecell(m,x,y, dispersal))<0) return 0; r=rand(); @@ -815,33 +818,24 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,struct } tick = gettick(); - if(first_sd) { - fitem->first_get_id = first_sd->bl.id; - if(type) - fitem->first_get_tick = tick + battle_config.mvp_item_first_get_time; - else - fitem->first_get_tick = tick + battle_config.item_first_get_time; - } - if(second_sd) { - fitem->second_get_id = second_sd->bl.id; - if(type) - fitem->second_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time; - else - fitem->second_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time; - } - if(third_sd) { - fitem->third_get_id = third_sd->bl.id; - if(type) - fitem->third_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time + battle_config.mvp_item_third_get_time; - else - fitem->third_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time + battle_config.item_third_get_time; - } + + if (owners[0]) + fitem->first_get_id = owners[0]->bl.id; + fitem->first_get_tick = tick + owner_protection[0]; + + if (owners[1]) + fitem->second_get_id = owners[1]->bl.id; + fitem->second_get_tick = tick + owner_protection[1]; + + if (owners[2]) + fitem->third_get_id = owners[2]->bl.id; + fitem->third_get_tick = tick + owner_protection[2]; memcpy(&fitem->item_data,item_data,sizeof(*item_data)); fitem->item_data.amount=amount; fitem->subx=(r&3)*3+3; fitem->suby=((r>>2)&3)*3+3; - fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0); + fitem->cleartimer=add_timer(gettick() + lifetime, map_clearflooritem_timer, fitem->bl.id, 0); map_addblock(&fitem->bl); clif_dropflooritem(fitem); @@ -849,6 +843,93 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,struct return fitem->bl.id; } + +int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,struct map_session_data *first_sd, + struct map_session_data *second_sd,struct map_session_data *third_sd,int type) +{ + struct map_session_data *owners[3] = { first_sd, second_sd, third_sd }; + int owner_protection[3]; + + if (type) { + owner_protection[0] = battle_config.mvp_item_first_get_time; + owner_protection[1] = owner_protection[0] + battle_config.mvp_item_second_get_time; + owner_protection[2] = owner_protection[1] + battle_config.mvp_item_third_get_time; + } else { + owner_protection[0] = battle_config.item_first_get_time; + owner_protection[1] = owner_protection[0] + battle_config.item_second_get_time; + owner_protection[2] = owner_protection[1] + battle_config.item_third_get_time; + } + + return map_addflooritem_any(item_data, amount, m, x, y, + owners, owner_protection, + battle_config.flooritem_lifetime, + 1); +} + +/* int xy,r; */ +/* unsigned int tick; */ +/* struct flooritem_data *fitem=NULL; */ + +/* nullpo_retr(0, item_data); */ + +/* if((xy=map_searchrandfreecell(m,x,y,1))<0) */ +/* return 0; */ +/* r=rand(); */ + +/* fitem = (struct flooritem_data *)aCalloc(1,sizeof(*fitem)); */ +/* fitem->bl.type=BL_ITEM; */ +/* fitem->bl.prev = fitem->bl.next = NULL; */ +/* fitem->bl.m=m; */ +/* fitem->bl.x=xy&0xffff; */ +/* fitem->bl.y=(xy>>16)&0xffff; */ +/* fitem->first_get_id = 0; */ +/* fitem->first_get_tick = 0; */ +/* fitem->second_get_id = 0; */ +/* fitem->second_get_tick = 0; */ +/* fitem->third_get_id = 0; */ +/* fitem->third_get_tick = 0; */ + +/* fitem->bl.id = map_addobject(&fitem->bl); */ +/* if(fitem->bl.id==0){ */ +/* free(fitem); */ +/* return 0; */ +/* } */ + +/* tick = gettick(); */ +/* if(first_sd) { */ +/* fitem->first_get_id = first_sd->bl.id; */ +/* if(type) */ +/* fitem->first_get_tick = tick + battle_config.mvp_item_first_get_time; */ +/* else */ +/* fitem->first_get_tick = tick + battle_config.item_first_get_time; */ +/* } */ +/* if(second_sd) { */ +/* fitem->second_get_id = second_sd->bl.id; */ +/* if(type) */ +/* fitem->second_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time; */ +/* else */ +/* fitem->second_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time; */ +/* } */ +/* if(third_sd) { */ +/* fitem->third_get_id = third_sd->bl.id; */ +/* if(type) */ +/* fitem->third_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time + battle_config.mvp_item_third_get_time; */ +/* else */ +/* fitem->third_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time + battle_config.item_third_get_time; */ +/* } */ + +/* memcpy(&fitem->item_data,item_data,sizeof(*item_data)); */ +/* fitem->item_data.amount=amount; */ +/* fitem->subx=(r&3)*3+3; */ +/* fitem->suby=((r>>2)&3)*3+3; */ +/* fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0); */ + +/* map_addblock(&fitem->bl); */ +/* clif_dropflooritem(fitem); */ + +/* return fitem->bl.id; */ +/* } */ + /*========================================== * charid_dbへ追加(返信待ちがあれば返信) *------------------------------------------ diff --git a/src/map/map.h b/src/map/map.h index ea240f2..dfed77f 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -686,6 +686,10 @@ int map_addnpc(int,struct npc_data *); // 床アイテム関連 int map_clearflooritem_timer(int,unsigned int,int,int); #define map_clearflooritem(id) map_clearflooritem_timer(0,0,id,1) +int map_addflooritem_any(struct item *,int amount,int m,int x,int y, + struct map_session_data **owners, + int *owner_protection, + int lifetime, int dispersal); int map_addflooritem(struct item *,int,int,int,int,struct map_session_data *,struct map_session_data *,struct map_session_data *,int); int map_searchrandfreecell(int,int,int,int); diff --git a/src/map/pc.c b/src/map/pc.c index 64057e7..2d4e48c 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3058,19 +3058,24 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) fitem->third_get_id = 0; } +fprintf(stderr, "pickuptime = %d, ticktime = %d\n", fitem->first_get_tick, tick); +fprintf(stderr, "canpickup-1 = %d\n", can_pick_item_up_from (sd, fitem->second_get_id)); can_take = can_pick_item_up_from (sd, fitem->first_get_id); - +fprintf(stderr, "Can take at L%d? %d\n", __LINE__, can_take); if (!can_take) can_take = fitem->first_get_tick <= tick && can_pick_item_up_from (sd, fitem->second_get_id); +fprintf(stderr, "Can take at L%d? %d\n", __LINE__, can_take); if (!can_take) can_take = fitem->second_get_tick <= tick && can_pick_item_up_from (sd, fitem->third_get_id); +fprintf(stderr, "Can take at L%d? %d\n", __LINE__, can_take); if (!can_take) can_take = fitem->third_get_tick <= tick; +fprintf(stderr, "Can take at L%d? %d\n", __LINE__, can_take); if (can_take) { /* Can pick up */ |