Hello. I've noticed some monsters don't use wands/rods/horns anymore. Tracking the issue, I found some hints: * monster_check_apply, which is used when a just generated item is put in monster inventory, will use manual_apply on the rod/wand/horn. Which checks for skill, ie 'use magic item'. But sometimes the monster doesn't have it yet (treasure list _after_ current one). * even if the monster has it 'FLAG_CAN_USE_SKILL' is not set, so skill can't be used. * also, change_skill is called for monsters when applying item, thus crash (who->contr == NULL) I attached a patch that enables monsters to fire their favorite wand/horn/rod :) It's dirty, and probably has some redundance (like 'FLAG_APPLIED' is set, but never really tested) Basically i grabbed the wand/rod firing code from server/player.c:fire_misc_object( ), and pasted it in server/monster.c:monster_use_range( ) to actually fire rod/bow. I think we should, at some point, use only one logic for players / monsters when firing bow/range, and for skills/spells too. Though java editor can't link between 'can use wands' flag and the 'use magic item' skill which is required, so that isn't great. Ryo -------------- next part -------------- Index: server/monster.c =================================================================== RCS file: /cvsroot/crossfire/crossfire/server/monster.c,v retrieving revision 1.69 diff -u -r1.69 monster.c --- server/monster.c 14 Apr 2004 07:24:30 -0000 1.69 +++ server/monster.c 8 May 2004 10:05:59 -0000 @@ -894,8 +894,10 @@ /* Monster will use a ranged spell attack. */ -int monster_use_range(object *head,object *part,object *pl,int dir) { +int monster_use_range(object *head,object *part,object *pl,int dir) + { object *wand, *owner; + int at_least_one = 0; if(!(dir=path_to_player(part,pl,0))) return 0; @@ -909,49 +911,54 @@ dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); for(wand=head->inv;wand!=NULL;wand=wand->below) - if(QUERY_FLAG(wand,FLAG_APPLIED) && - (wand->type == WAND || wand->type == ROD || wand->type==HORN)) - break; + { + if (wand->type == WAND) + { + /* Found a wand, let's see if it has charges left */ + at_least_one = 1; + if( wand->stats.food<=0 ) + continue; + + cast_spell( head, wand, dir, wand->inv, NULL ); + + if ( !( --wand->stats.food ) ) + { + object *tmp; + if ( wand->arch ) + { + CLEAR_FLAG(wand, FLAG_ANIMATE); + wand->face = wand->arch->clone.face; + wand->speed = 0; + update_ob_speed(wand); + } + } + /* Success */ + return 1; + } + else if ( wand->type == ROD || wand->type==HORN ) + { + /* Found rod/horn, let's use it if possible */ + at_least_one = 1; + if( wand->stats.hp < MAX( wand->inv->stats.sp, wand->inv->stats.grace ) ) + continue; + + cast_spell( head, wand, dir, wand->inv, NULL ); + + drain_rod_charge( wand ); + + /* Success */ + return 1; + } + } + + if ( at_least_one ) + return 0; - if(wand==NULL) { - LOG(llevError,"Error: Monster %s (%d) HAS_READY_RANG() without range.\n", + LOG(llevError,"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->name,head->count); CLEAR_FLAG(head, FLAG_READY_RANGE); return 0; } - if (!wand->inv) { - LOG(llevError,"Wand %s lacks spell\n", wand->name); - return 0; - } - if (wand->type == WAND) { - if(wand->stats.food<=0) { - manual_apply(head,wand,0); - CLEAR_FLAG(head, FLAG_READY_RANGE); - if (wand->arch) { - CLEAR_FLAG(wand, FLAG_ANIMATE); - wand->face = wand->arch->clone.face; - wand->speed = 0; - update_ob_speed(wand); - } - return 0; - } - } - else { - if(wand->stats.hp<MAX(wand->inv->stats.sp, wand->inv->stats.grace)) - return 0; /* Not recharged enough yet */ - } - - /* Spell should be cast on caster (ie, heal, strength) */ - if (wand->inv->range==0) - dir = 0; - - if(cast_spell(part,wand,dir,wand->inv,NULL)) { - if (wand->type==WAND) - wand->stats.food--; - return 1; - } - return 0; -} int monster_use_bow(object *head, object *part, object *pl, int dir) { object *owner; @@ -1246,16 +1253,40 @@ else if (item->type == WEAPON) flag = check_good_weapon(mon,item); else if (IS_ARMOR(item)) flag = check_good_armour(mon,item); /* Should do something more, like make sure this is a better item */ - else if (item->type == SKILL || item->type == RING || item->type==WAND || - item->type == ROD || item->type==HORN) flag=1; + else if (item->type == RING) + flag=1; + else if ( item->type==WAND || item->type == ROD || item->type==HORN ) + { + /* We never really 'ready' the wand/rod/horn, because that would mean the + * weapon would get undone. + */ + if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK)) + { + SET_FLAG(mon, FLAG_READY_RANGE); + SET_FLAG(item, FLAG_APPLIED); + } + return; + } else if (item->type == BOW) { - /* We never really 'ready' the bow, because that would mean the - * weapon would get undone. - */ - if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK)) - SET_FLAG(mon, FLAG_READY_BOW); - return; - } + /* We never really 'ready' the bow, because that would mean the + * weapon would get undone. + */ + if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK)) + SET_FLAG(mon, FLAG_READY_BOW); + return; + } + else if ( item->type == SKILL ) + { + /* + * Ryo 2004-05-08 + * skills are specials: monsters must have the 'FLAG_CAN_USE_SKILL' flag set, + * else they can't use the skill... + * Skills also don't need to get applied, so return now. + */ + SET_FLAG( item, FLAG_CAN_USE_SKILL ); + return; + } + /* if we don't match one of the above types, return now. * can_apply_object will say that we can apply things like flesh, @@ -1270,7 +1301,6 @@ */ if (can_apply_object(mon, item) & CAN_APPLY_NOT_MASK) return; - /* should only be applying this item, not unapplying it. * also, ignore status of curse so they can take off old armour. * monsters have some advantages after all. Index: server/skill_util.c =================================================================== RCS file: /cvsroot/crossfire/crossfire/server/skill_util.c,v retrieving revision 1.47 diff -u -r1.47 skill_util.c --- server/skill_util.c 8 Apr 2004 06:48:51 -0000 1.47 +++ server/skill_util.c 8 May 2004 10:06:01 -0000 @@ -229,7 +229,12 @@ int change_skill (object *who, object *new_skill, int flag) { - int old_range = who->contr->shoottype; + int old_range; + + if ( who->type != PLAYER ) + return 0; + + old_range = who->contr->shoottype; if (who->chosen_skill && who->chosen_skill == new_skill) { -------------- next part -------------- _______________________________________________ crossfire-devel mailing list crossfire-devel at lists.real-time.com https://mailman.real-time.com/mailman/listinfo/crossfire-devel