1 | /* |
1 | /* |
2 | * static char *rcsid_apply_c = |
2 | * static char *rcsid_apply_c = |
3 | * "$Id: apply.C,v 1.9 2006/08/25 17:11:53 root Exp $"; |
3 | * "$Id: apply.C,v 1.13 2006/08/29 07:34:00 root Exp $"; |
4 | */ |
4 | */ |
5 | /* |
5 | /* |
6 | CrossFire, A Multiplayer game for X-windows |
6 | CrossFire, A Multiplayer game for X-windows |
7 | |
7 | |
8 | Copyright (C) 2001 Mark Wedel & Crossfire Development Team |
8 | Copyright (C) 2001 Mark Wedel & Crossfire Development Team |
… | |
… | |
38 | /* Want this regardless of rplay. */ |
38 | /* Want this regardless of rplay. */ |
39 | #include <sounds.h> |
39 | #include <sounds.h> |
40 | |
40 | |
41 | /* need math lib for double-precision and pow() in dragon_eat_flesh() */ |
41 | /* need math lib for double-precision and pow() in dragon_eat_flesh() */ |
42 | #include <math.h> |
42 | #include <math.h> |
43 | |
|
|
44 | /* Can transport hold object op? |
|
|
45 | * This is a pretty trivial function, |
|
|
46 | * but in the future, possible transport may have more restrictions |
|
|
47 | * or weight reduction like containers |
|
|
48 | */ |
|
|
49 | int transport_can_hold(const object *transport, const object *op, int nrof) |
|
|
50 | { |
|
|
51 | if ((op->weight *nrof + transport->carrying) > transport->weight_limit) |
|
|
52 | return 0; |
|
|
53 | else |
|
|
54 | return 1; |
|
|
55 | } |
|
|
56 | |
|
|
57 | |
|
|
58 | /* |
|
|
59 | * Player is trying to use a transport. This returns same values as |
|
|
60 | * manual_apply() does. This function basically checks to see if |
|
|
61 | * the player can use the transport, and if so, sets up the appropriate |
|
|
62 | * pointers. |
|
|
63 | */ |
|
|
64 | int apply_transport(object *pl, object *transport, int aflag) { |
|
|
65 | |
|
|
66 | /* Only players can use transports right now */ |
|
|
67 | if (pl->type != PLAYER) return 0; |
|
|
68 | |
|
|
69 | // due to brokenness of transports disable them until a working alternative |
|
|
70 | // has been found... :( |
|
|
71 | // - elmex |
|
|
72 | new_draw_info (NDI_UNIQUE, 0, pl, "This transport is out of order!"); |
|
|
73 | return 1; |
|
|
74 | |
|
|
75 | /* If player is currently on a transport but not this transport, they need |
|
|
76 | * to exit first. Perhaps transport to transport transfers should be |
|
|
77 | * allowed. |
|
|
78 | */ |
|
|
79 | if (pl->contr->transport && pl->contr->transport != transport) { |
|
|
80 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
81 | "You must exit %s before you can board %s.", |
|
|
82 | query_name(pl->contr->transport), |
|
|
83 | query_name(transport)); |
|
|
84 | return 1; |
|
|
85 | } |
|
|
86 | |
|
|
87 | /* player is currently on a transport. This must mean he |
|
|
88 | * wants to exit. |
|
|
89 | */ |
|
|
90 | if (pl->contr->transport) { |
|
|
91 | object *old_transport = pl->contr->transport, *inv; |
|
|
92 | |
|
|
93 | /* Should we print a message if the player only wants to |
|
|
94 | * apply? |
|
|
95 | */ |
|
|
96 | if (aflag & AP_APPLY) return 1; |
|
|
97 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
98 | "You disembark from %s.", |
|
|
99 | query_name(old_transport)); |
|
|
100 | remove_ob(pl); |
|
|
101 | pl->map = old_transport->map; |
|
|
102 | pl->x = old_transport->x; |
|
|
103 | pl->y = old_transport->y; |
|
|
104 | if (pl->contr == old_transport->contr) |
|
|
105 | old_transport->contr = NULL; |
|
|
106 | |
|
|
107 | pl->contr->transport = NULL; |
|
|
108 | insert_ob_in_map(pl, pl->map, pl, 0); |
|
|
109 | sum_weight(old_transport); |
|
|
110 | |
|
|
111 | /* Possible for more than one player to be using a transport. |
|
|
112 | * if that is the case, we don't want to reset the face, as the |
|
|
113 | * transport is still occupied. |
|
|
114 | */ |
|
|
115 | for (inv=old_transport->inv; inv; inv=inv->below) |
|
|
116 | if (inv->type == PLAYER) break; |
|
|
117 | if (!inv) { |
|
|
118 | old_transport->face = old_transport->arch->clone.face; |
|
|
119 | old_transport->animation_id = old_transport->arch->clone.animation_id; |
|
|
120 | } |
|
|
121 | return 1; |
|
|
122 | } |
|
|
123 | else { |
|
|
124 | /* player is trying to board a transport */ |
|
|
125 | int pc=0, p_limit; |
|
|
126 | object *inv; |
|
|
127 | const char *kv; |
|
|
128 | |
|
|
129 | if (aflag & AP_UNAPPLY) return 1; |
|
|
130 | |
|
|
131 | /* Can this transport hold the weight of this player? */ |
|
|
132 | if (!transport_can_hold(transport, pl, 1)) { |
|
|
133 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
134 | "The %s is unable to hold your weight!", |
|
|
135 | query_name(transport)); |
|
|
136 | return 1; |
|
|
137 | } |
|
|
138 | |
|
|
139 | /* Does this transport have space for more players? */ |
|
|
140 | for (inv=transport->inv; inv; inv=inv->below) { |
|
|
141 | if (inv->type == PLAYER) pc++; |
|
|
142 | } |
|
|
143 | kv = get_ob_key_value(transport, "passenger_limit"); |
|
|
144 | if (!kv) p_limit=1; |
|
|
145 | else p_limit = atoi(kv); |
|
|
146 | if (pc >= p_limit) { |
|
|
147 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
148 | "The %s does not have space for any more people", |
|
|
149 | query_name(transport)); |
|
|
150 | return 1; |
|
|
151 | } |
|
|
152 | |
|
|
153 | /* Everything checks out OK - player can get on the transport */ |
|
|
154 | pl->contr->transport = transport; |
|
|
155 | if (!transport->contr) transport->contr = pl->contr; |
|
|
156 | remove_ob(pl); |
|
|
157 | insert_ob_in_ob(pl, transport); |
|
|
158 | sum_weight(transport); |
|
|
159 | pl->map = transport->map; |
|
|
160 | pl->x = transport->x; |
|
|
161 | pl->y = transport->y; |
|
|
162 | |
|
|
163 | /* Might need to update face, animation info */ |
|
|
164 | if (!pc) { |
|
|
165 | const char *str; |
|
|
166 | |
|
|
167 | str = get_ob_key_value(transport, "face_full"); |
|
|
168 | if (str) |
|
|
169 | transport->face = &new_faces[FindFace(str, |
|
|
170 | transport->face->number)]; |
|
|
171 | str = get_ob_key_value(transport, "anim_full"); |
|
|
172 | if (str) |
|
|
173 | transport->animation_id = find_animation(str); |
|
|
174 | } |
|
|
175 | |
|
|
176 | /* Does speed of this object change based on weight? */ |
|
|
177 | kv = get_ob_key_value(transport, "weight_speed_ratio"); |
|
|
178 | if (kv) { |
|
|
179 | int wsr = atoi(kv); |
|
|
180 | float base_speed; |
|
|
181 | |
|
|
182 | kv = get_ob_key_value(transport, "base_speed"); |
|
|
183 | if (kv) base_speed = atof(kv); |
|
|
184 | else base_speed = transport->arch->clone.speed; |
|
|
185 | |
|
|
186 | transport->speed = base_speed - (base_speed * transport->carrying * |
|
|
187 | wsr) / (transport->weight_limit * 100); |
|
|
188 | |
|
|
189 | /* Put some limits on min/max speeds */ |
|
|
190 | if (transport->speed < 0.10) transport->speed = 0.10; |
|
|
191 | if (transport->speed > 1.0) transport->speed = 1.0; |
|
|
192 | } |
|
|
193 | } /* else if player is boarding the transport */ |
|
|
194 | |
|
|
195 | return 1; |
|
|
196 | } |
|
|
197 | |
|
|
198 | |
|
|
199 | |
43 | |
200 | /** |
44 | /** |
201 | * Check if op should abort moving victim because of it's race or slaying. |
45 | * Check if op should abort moving victim because of it's race or slaying. |
202 | * Returns 1 if it should abort, returns 0 if it should continue. |
46 | * Returns 1 if it should abort, returns 0 if it should continue. |
203 | */ |
47 | */ |
… | |
… | |
1291 | |
1135 | |
1292 | if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) { |
1136 | if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) { |
1293 | if (op->container->env != op) { /* if container is on the ground */ |
1137 | if (op->container->env != op) { /* if container is on the ground */ |
1294 | op->container->move_off = 0; |
1138 | op->container->move_off = 0; |
1295 | } |
1139 | } |
1296 | /* Lauwenmark: Handle for plugin close event */ |
1140 | |
1297 | if (execute_event(tmp, EVENT_CLOSE,op,NULL,NULL,SCRIPT_FIX_ALL)!=0) |
1141 | if (INVOKE_OBJECT (CLOSE, op)) |
1298 | return 1; |
1142 | return 1; |
1299 | |
1143 | |
1300 | new_draw_info_format(NDI_UNIQUE, 0, op, "You close %s.", |
1144 | new_draw_info_format(NDI_UNIQUE, 0, op, "You close %s.", |
1301 | query_name(op->container)); |
1145 | query_name(op->container)); |
1302 | CLEAR_FLAG(op->container, FLAG_APPLIED); |
1146 | CLEAR_FLAG(op->container, FLAG_APPLIED); |
1303 | op->container=NULL; |
1147 | op->container=NULL; |
… | |
… | |
1576 | return; |
1420 | return; |
1577 | } |
1421 | } |
1578 | recursion_depth++; |
1422 | recursion_depth++; |
1579 | if (trap->head) trap=trap->head; |
1423 | if (trap->head) trap=trap->head; |
1580 | |
1424 | |
1581 | /* Lauwenmark: Handle for plugin trigger event */ |
1425 | if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
1582 | if (execute_event(trap, EVENT_TRIGGER,originator,victim,NULL,SCRIPT_FIX_ALL)!=0) |
|
|
1583 | goto leave; |
1426 | goto leave; |
1584 | |
1427 | |
1585 | switch (trap->type) { |
1428 | switch (trap->type) { |
1586 | case PLAYERMOVER: |
1429 | case PLAYERMOVER: |
1587 | if (trap->attacktype && (trap->level || victim->type!=PLAYER) && |
1430 | if (trap->attacktype && (trap->level || victim->type!=PLAYER) && |
… | |
… | |
2546 | } else { |
2389 | } else { |
2547 | return 0; /* monsters just skip unpaid items */ |
2390 | return 0; /* monsters just skip unpaid items */ |
2548 | } |
2391 | } |
2549 | } |
2392 | } |
2550 | |
2393 | |
2551 | |
|
|
2552 | /* Lauwenmark: Handle for plugin apply event */ |
|
|
2553 | //TODO: remove |
|
|
2554 | if (execute_event(tmp, EVENT_APPLY,op,NULL,NULL,SCRIPT_FIX_ALL)!=0) |
|
|
2555 | return 1; |
|
|
2556 | |
|
|
2557 | if (INVOKE_OBJECT (APPLY, tmp, ARG_OBJECT (op))) |
2394 | if (INVOKE_OBJECT (APPLY, tmp, ARG_OBJECT (op))) |
2558 | return 1; |
2395 | return RESULT_INT (0); |
2559 | |
2396 | |
2560 | switch (tmp->type) { |
2397 | switch (tmp->type) { |
2561 | |
|
|
2562 | case TRANSPORT: |
|
|
2563 | return apply_transport(op, tmp, aflag); |
|
|
2564 | |
2398 | |
2565 | case CF_HANDLE: |
2399 | case CF_HANDLE: |
2566 | new_draw_info(NDI_UNIQUE, 0,op,"You turn the handle."); |
2400 | new_draw_info(NDI_UNIQUE, 0,op,"You turn the handle."); |
2567 | play_sound_map(op->map, op->x, op->y, SOUND_TURN_HANDLE); |
2401 | play_sound_map(op->map, op->x, op->y, SOUND_TURN_HANDLE); |
2568 | tmp->value=tmp->value?0:1; |
2402 | tmp->value=tmp->value?0:1; |
… | |
… | |
2811 | void player_apply_below (object *pl) |
2645 | void player_apply_below (object *pl) |
2812 | { |
2646 | { |
2813 | object *tmp, *next; |
2647 | object *tmp, *next; |
2814 | int floors; |
2648 | int floors; |
2815 | |
2649 | |
2816 | if (pl->contr->transport && pl->contr->transport->type == TRANSPORT) { |
|
|
2817 | apply_transport(pl, pl->contr->transport, 0); |
|
|
2818 | return; |
|
|
2819 | } |
|
|
2820 | |
|
|
2821 | /* If using a container, set the starting item to be the top |
2650 | /* If using a container, set the starting item to be the top |
2822 | * item in the container. Otherwise, use the map. |
2651 | * item in the container. Otherwise, use the map. |
2823 | */ |
2652 | */ |
2824 | tmp = (pl->container != NULL) ? pl->container->inv : pl->below; |
2653 | tmp = (pl->container != NULL) ? pl->container->inv : pl->below; |
2825 | |
2654 | |
… | |
… | |
2856 | * Break this out of apply_special - this is just done |
2685 | * Break this out of apply_special - this is just done |
2857 | * to keep the size of apply_special to a more managable size. |
2686 | * to keep the size of apply_special to a more managable size. |
2858 | */ |
2687 | */ |
2859 | static int unapply_special (object *who, object *op, int aflags) |
2688 | static int unapply_special (object *who, object *op, int aflags) |
2860 | { |
2689 | { |
|
|
2690 | if (INVOKE_OBJECT (BE_UNREADY, op, ARG_OBJECT (who), ARG_INT (aflags)) |
|
|
2691 | || INVOKE_OBJECT (UNREADY, who, ARG_OBJECT (op), ARG_INT (aflags))) |
|
|
2692 | return RESULT_INT (0); |
|
|
2693 | |
2861 | object *tmp2; |
2694 | object *tmp2; |
2862 | |
2695 | |
2863 | CLEAR_FLAG(op, FLAG_APPLIED); |
2696 | CLEAR_FLAG(op, FLAG_APPLIED); |
2864 | switch(op->type) { |
2697 | switch(op->type) { |
2865 | case WEAPON: |
2698 | case WEAPON: |
2866 | new_draw_info_format(NDI_UNIQUE, 0, who, "You unwield %s.",query_name(op)); |
2699 | new_draw_info_format(NDI_UNIQUE, 0, who, "You unwield %s.",query_name(op)); |
2867 | |
2700 | |
2868 | (void) change_abil (who,op); |
2701 | (void) change_abil (who,op); |
2869 | if(QUERY_FLAG(who,FLAG_READY_WEAPON)) |
2702 | if(QUERY_FLAG(who,FLAG_READY_WEAPON)) |
2870 | CLEAR_FLAG(who,FLAG_READY_WEAPON); |
2703 | CLEAR_FLAG(who,FLAG_READY_WEAPON); |
2871 | /* GROS: update the current_weapon_script field (used with script_attack for weapons) */ |
|
|
2872 | who->current_weapon_script = NULL; |
|
|
2873 | who->current_weapon = NULL; |
|
|
2874 | clear_skill(who); |
2704 | clear_skill(who); |
2875 | break; |
2705 | break; |
2876 | |
2706 | |
2877 | case SKILL: /* allows objects to impart skills */ |
2707 | case SKILL: /* allows objects to impart skills */ |
2878 | case SKILL_TOOL: |
2708 | case SKILL_TOOL: |
… | |
… | |
3113 | * See include/define.h for detailed description of the meaning of |
2943 | * See include/define.h for detailed description of the meaning of |
3114 | * these return values. |
2944 | * these return values. |
3115 | */ |
2945 | */ |
3116 | int can_apply_object(object *who, object *op) |
2946 | int can_apply_object(object *who, object *op) |
3117 | { |
2947 | { |
|
|
2948 | if (INVOKE_OBJECT (CAN_BE_APPLIED, op, ARG_OBJECT (who)) |
|
|
2949 | || INVOKE_OBJECT (CAN_APPLY, who, ARG_OBJECT (op))) |
|
|
2950 | return RESULT_INT (0); |
|
|
2951 | |
3118 | int i, retval=0; |
2952 | int i, retval=0; |
3119 | object *tmp=NULL, *ws=NULL; |
2953 | object *tmp=NULL, *ws=NULL; |
3120 | |
2954 | |
3121 | /* Players have 2 'arm's, so they could in theory equip 2 shields or |
2955 | /* Players have 2 'arm's, so they could in theory equip 2 shields or |
3122 | * 2 weapons, but we don't want to let them do that. So if they are |
2956 | * 2 weapons, but we don't want to let them do that. So if they are |
… | |
… | |
3340 | if(op->nrof > 1) |
3174 | if(op->nrof > 1) |
3341 | tmp = get_split_ob(op,op->nrof - 1); |
3175 | tmp = get_split_ob(op,op->nrof - 1); |
3342 | else |
3176 | else |
3343 | tmp = NULL; |
3177 | tmp = NULL; |
3344 | |
3178 | |
|
|
3179 | if (INVOKE_OBJECT (BE_READY, op, ARG_OBJECT (who)) |
|
|
3180 | || INVOKE_OBJECT (READY, who, ARG_OBJECT (op))) |
|
|
3181 | return RESULT_INT (0); |
|
|
3182 | |
3345 | switch(op->type) { |
3183 | switch(op->type) { |
3346 | case WEAPON: |
3184 | case WEAPON: |
3347 | if (!check_weapon_power(who, op->last_eat)) { |
3185 | if (!check_weapon_power(who, op->last_eat)) { |
3348 | new_draw_info(NDI_UNIQUE, 0,who, |
3186 | new_draw_info(NDI_UNIQUE, 0,who, |
3349 | "That weapon is too powerful for you to use."); |
3187 | "That weapon is too powerful for you to use."); |
… | |
… | |
3367 | SET_FLAG(who, FLAG_READY_WEAPON); |
3205 | SET_FLAG(who, FLAG_READY_WEAPON); |
3368 | |
3206 | |
3369 | new_draw_info_format(NDI_UNIQUE, 0, who, "You wield %s.",query_name(op)); |
3207 | new_draw_info_format(NDI_UNIQUE, 0, who, "You wield %s.",query_name(op)); |
3370 | |
3208 | |
3371 | (void) change_abil (who,op); |
3209 | (void) change_abil (who,op); |
3372 | /* GROS: update the current_weapon_script field (used with EVENT_ATTACK for weapons) */ |
|
|
3373 | /*if ((evt = find_event(op, EVENT_ATTACK)) != NULL) { |
|
|
3374 | LOG(llevDebug, "Scripting Weapon wielded\n"); |
|
|
3375 | if (who->current_weapon_script) free_string(who->current_weapon_script); |
|
|
3376 | who->current_weapon_script=add_string(query_name(op)); |
|
|
3377 | } |
|
|
3378 | who->current_weapon = op;*/ |
|
|
3379 | break; |
3210 | break; |
3380 | |
3211 | |
3381 | case ARMOUR: |
3212 | case ARMOUR: |
3382 | case HELMET: |
3213 | case HELMET: |
3383 | case SHIELD: |
3214 | case SHIELD: |