summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spell-language21
-rw-r--r--src/map/magic-interpreter-base.c36
-rw-r--r--src/map/magic-interpreter.h5
-rw-r--r--src/map/magic-stmt.c115
-rw-r--r--src/map/magic.c8
-rw-r--r--src/map/map.c131
-rw-r--r--src/map/map.h4
-rw-r--r--src/map/pc.c7
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 */